143 Commits

Author SHA1 Message Date
c54b12181d clang format 2024-02-12 18:02:43 -06:00
26c0ba122f service: news: Stub remaining functions 2024-02-11 21:05:28 -06:00
905356ccfc launch 2024-02-11 21:05:28 -06:00
09ababeaad display titles 2024-02-11 21:05:28 -06:00
e58881cb9c fix user creation 2024-02-11 21:05:28 -06:00
f5bf73069d fix changing theme 2024-02-11 21:05:28 -06:00
8e3cd0a5b0 stubbs 2024-02-11 21:05:28 -06:00
10e54243e3 service: am: Implement remaining am functions needed by Qlaunch 2024-02-11 21:05:24 -06:00
9052a9b8ee fix settings 2024-02-11 21:04:25 -06:00
e2fe0c49b2 moar stubs 2024-02-11 21:04:25 -06:00
39af5495f4 service: Add even more stubs for Qlaunch 2024-02-11 21:04:25 -06:00
c3db1c4681 service: Add stubs for Qlaunch 2024-02-11 21:04:25 -06:00
2ff45cd0da Merge pull request #12756 from liamwhite/applet-multiprocess-hwc
general: applet multiprocess
2024-02-11 20:58:28 -06:00
b6b56f48b7 Merge pull request #12991 from german77/news2
service: news: Stub remaining functions
2024-02-11 21:44:23 -05:00
04a9d14f35 service: news: Stub remaining functions 2024-02-11 17:56:26 -06:00
98db796fde Merge pull request #12986 from t895/input-config-clear-fix
config: Always delete control settings in ClearControlPlayerValues
2024-02-11 12:24:18 -05:00
adebc96a9c config: Always delete control settings in ClearControlPlayerValues 2024-02-11 07:35:54 -05:00
564a65a82e Merge pull request #12981 from lat9nq/tzdb-asan-custom
tzdb_to_nx: Update to latest
2024-02-10 22:42:47 -05:00
501ff2eda5 Merge pull request #12980 from merryhime/race-me
dynarmic: Fix invalidation race
2024-02-10 22:42:42 -05:00
999ec5739d Merge pull request #12978 from liamwhite/ffs-qcom
host_shaders: add vendor workaround for adreno drivers
2024-02-10 22:42:25 -05:00
68b2db21b1 tzdb_to_nx: Update to latest
Includes memory leak fix.

Includes option to specify a custom zoneinfo dir.
2024-02-10 17:45:18 -05:00
2337397a15 Merge pull request #12969 from german77/bcat-interface
service: bcat: Migrate and refractor service to new IPC
2024-02-10 16:00:43 -05:00
7c56ecca3f Merge pull request #12949 from liamwhite/multi-wait
service: add os types and multi wait API
2024-02-10 16:00:34 -05:00
211544fbc8 externals: Update dynarmic to 6.6.3 2024-02-10 19:40:47 +00:00
4677fd3f64 am: use applet program loading for tested versions 2024-02-10 12:38:19 -05:00
4eeac731ff host_shaders: add vendor workaround for adreno drivers 2024-02-10 12:02:37 -05:00
816d03f7d9 service: bcat: Address review issues 2024-02-10 00:23:23 -06:00
909f7eb3d2 service: bcat: Implement news interfaces 2024-02-10 00:23:22 -06:00
7c2e9a6596 service: bcat: Migrate and refractor service to new IPC 2024-02-10 00:23:22 -06:00
fe6934593f Fix multiplayer player count color in dark themes | Temp fix until #12744: Add green color for counts > 0 and < max_players - 1 (#12930)
* fix intended player count color in dark themes

* Refactor

* Change to green color for white and dark themes

* Add const to the colors and extra name for green color
2024-02-09 18:45:11 -06:00
52c8adc7ed Merge pull request #12951 from liamwhite/more-ipc
ipc: additional fixes
2024-02-09 10:51:03 -06:00
7ec7ff0f30 Merge pull request #12920 from t895/jni-common
android: Move JNI setup and helpers to common
2024-02-09 11:49:25 -05:00
a133eadf06 Merge pull request #12927 from german77/cheat-pause
dmnt: cheat: Add pause and resume support
2024-02-09 11:47:34 -05:00
89dd0fa932 Merge pull request #12968 from t895/thermal-status
android: Thermal throttling indicator
2024-02-09 11:47:17 -05:00
a9dcfe2a42 Merge pull request #12964 from t895/foreground-service-test
android: Remove foreground service
2024-02-09 11:47:11 -05:00
2ad8d614b5 Merge pull request #12966 from german77/free_npad
service: hid: Free npad applet resource
2024-02-09 11:47:05 -05:00
b206ea5cfe am: fix focus states and display of indirect keyboard 2024-02-09 09:20:53 -05:00
70590f79f8 am: stub SetMediaPlaybackState for self controller 2024-02-09 09:20:53 -05:00
fa12384350 general: add default configurations for applet mode 2024-02-09 09:20:53 -05:00
78aac6b403 gpu: dependency-inject scaling/antialiasing filter state for capture layers 2024-02-09 09:20:53 -05:00
0cb413c3d3 nvnflinger/gpu: implement applet capture 2024-02-09 09:20:53 -05:00
962c82540c nvnflinger/gpu: implement blending 2024-02-09 09:20:53 -05:00
06fd7f2012 nvservices: unmap only on last container free 2024-02-09 09:20:53 -05:00
0cbb555e9a video_core: defensively program around unmapped device pointers 2024-02-09 09:20:53 -05:00
2e8c21ad2d core: fix multiprocess with nce 2024-02-09 09:20:53 -05:00
f44183db9e android: Use utility function for applying view margins 2024-02-09 07:07:06 -05:00
5fa9bc192c android: Add thermal throttling overlay 2024-02-09 07:07:05 -05:00
f9a559d2b7 Merge pull request #12967 from german77/let_me_out
service: Fix OutLargeData attributes
2024-02-08 21:33:22 -05:00
af87365672 android: Remove foreground service 2024-02-08 21:04:14 -05:00
03a23c037a service: Fix OutLargeData attributes 2024-02-08 19:40:06 -06:00
0ac777460d service: hid: Free npad applet resource 2024-02-08 18:50:54 -06:00
71e59bdcd8 Merge pull request #12963 from t895/versioning-fix
android: Fix regex for git version
2024-02-08 17:03:32 -05:00
0a1283f94f android: Fix regex for git version 2024-02-08 14:24:15 -05:00
2600ac65c8 android: Run OnEmulationStarted frontend callback in another thread
The JVM has problems with attaching to a Fiber so we start a new thread and wait for the result here.
2024-02-08 14:13:46 -05:00
c8e8c614a0 common: fs: Expand android macros 2024-02-08 14:13:46 -05:00
e7c4c8b993 android: Move JNI setup and helpers to common 2024-02-08 13:45:26 -05:00
f049453dd6 Merge pull request #12903 from liamwhite/const-offset
shader_recompiler: use only ConstOffset for OpImageFetch
2024-02-08 17:00:45 +01:00
cac37a6f6e Merge pull request #12954 from german77/hidbus-interface
service: hid: Migrate hidbus to new interface
2024-02-08 11:00:11 -05:00
263dfa95e4 Merge pull request #12914 from FernandoS27/vc-refactor
VideoCore Refactor Part 1.
2024-02-08 10:59:59 -05:00
bc9711cb1e Merge pull request #12953 from FernandoS27/zero-fps-mah-ass
SMMU: Ensure the backing address range matches the current
2024-02-08 10:59:52 -05:00
b4d88a7bb4 service: hid: Migrate hidbus to new interface 2024-02-07 18:07:32 -06:00
ae833aa9c0 SMMU: Ensure the backing address range matches the current 2024-02-07 23:47:42 +01:00
4463ded603 Merge pull request #12939 from german77/wonder
dmnt: cheat: Invalidate cache on memory writes
2024-02-07 15:33:44 -05:00
159dec01ee Merge pull request #12932 from german77/any-key-is-good
yuzu: Make controller keys easier to assign
2024-02-07 15:33:39 -05:00
6319bafafa Merge pull request #12912 from FearlessTobi/ports-feb-24
Port some small changes from Citra (web_backend and translations)
2024-02-07 15:33:28 -05:00
c000a5ff09 Merge pull request #12909 from t895/play-store-automation
ci: android: Play store publishing setup
2024-02-07 15:32:42 -05:00
fee263c59c ipc: additional fixes 2024-02-07 15:06:15 -05:00
5a64a77df3 glue: use multi wait API 2024-02-07 12:15:01 -05:00
6810929f6a server_manager: use multi wait API 2024-02-07 12:15:01 -05:00
9404633bfd service: add os types and multi wait API 2024-02-07 12:14:46 -05:00
12f86f89fc yuzu: Make controller keys easier to assign 2024-02-06 16:51:39 -06:00
9858ea79fb dmnt: cheat: Invalidate cache on memory writes 2024-02-06 13:49:48 -06:00
c10e720ba9 Merge pull request #12883 from FernandoS27/memory_manager_mem
MemoryManager: Reduce the page table size based on last big page address.
2024-02-06 10:25:03 -05:00
5016de3626 Merge pull request #12928 from german77/motion-mp
service: hid: Add multiprocess support to six axis input
2024-02-06 10:24:46 -05:00
d5fb9fd12c Merge pull request #12933 from german77/irs-interface
service: irs: Migrate service to new interface
2024-02-06 10:24:30 -05:00
c79b3af610 Merge pull request #12934 from german77/hid_debug_interface
service: hid: Migrate hid debug service to new interface
2024-02-06 10:24:20 -05:00
c0a383d960 web_backend: Fix compilation 2024-02-06 15:48:04 +01:00
b6106604c4 service: hid: Migrate hid debug service to new interface 2024-02-06 00:38:46 -06:00
12b6162852 service: irs: Migrate service to new interface 2024-02-06 00:14:16 -06:00
8f192b494a service: hid: Add multiprocess support to six axis input 2024-02-05 17:19:31 -06:00
372897aac4 service: hid: Ensure aruid data is initialized 2024-02-05 17:17:21 -06:00
fa47ac1c9f Common: Rename SplitRangeSet to OverlapRangeSet 2024-02-05 23:01:17 +01:00
c52d7cc694 dmnt: cheat: Add pause and resume support 2024-02-05 14:38:26 -06:00
a2f23746c2 Merge pull request #12905 from liamwhite/hwc-release
nvnflinger: release buffers before presentation sleep
2024-02-05 13:43:22 -05:00
215b13f2a2 Merge pull request #12924 from liamwhite/pedantic-unsigned
typed_address: test values are unsigned
2024-02-05 13:43:06 -05:00
35ed9425d7 Merge pull request #12925 from german77/linux-tab
yuzu: Fully hide linux tab
2024-02-05 13:41:31 -05:00
74cc8721c7 Merge pull request #12915 from german77/cheat
dmnt: cheats: Update cheat vm to latest version
2024-02-05 13:41:21 -05:00
8ef1db78b0 Merge pull request #12916 from liamwhite/float-fix
gdb: fix load/save of fp values in a32
2024-02-05 13:41:15 -05:00
18c8f10ff2 Merge pull request #12922 from FearlessTobi/lang-mappins
.tx/config: Use language mappings for android "tx pull"
2024-02-05 13:40:53 -05:00
96d881f087 yuzu: Fully hide linux tab 2024-02-05 11:58:20 -06:00
0e950baf41 typed_address: test values are unsigned 2024-02-05 12:47:10 -05:00
8113f55f4b dmnt: cheats: Silence memory errors 2024-02-05 11:08:24 -06:00
f296a9ce9a shader_recompiler: use only ConstOffset for OpImageFetch 2024-02-05 12:01:09 -05:00
ddbefc71cb .tx/config: Use language mappings for android "tx pull"
The language names we are using in the android resources differ from those on Transifex.

We need to manually specify mappings for them, so Transifex is able to place the files in the correct folders.
2024-02-05 15:57:13 +01:00
0d5a3abeae Buffer Cache: Refactor to use Range sets instead 2024-02-05 11:06:52 +01:00
85143e8376 gdb: fix load/save of fp values in a32 2024-02-04 20:28:43 -05:00
504abbd6e0 dmnt: cheats: Update cheat vm to latest version 2024-02-04 17:46:20 -06:00
accccc0cbf NVDRV: Refactor HeapMapper to use RangeSets 2024-02-04 20:01:50 +01:00
01ba6cf610 Common: Introduce Range Sets 2024-02-04 20:01:50 +01:00
4841dc0b74 VideoCore: Move Slot Vector to Common 2024-02-04 20:01:47 +01:00
185125e4e4 citra_qt/configure_ui: Show country of language in the combobox
This prevents an issue where we had seperate versions of the same language for different regions and they were not distinguishable (e.g. "Chinese (China)" and "Chinese (Taiwan)").

Also makes it so we do not need to hardcode specific languages anymore.
2024-02-04 17:06:44 +01:00
99ea31faa8 ci: android: Play store publishing setup 2024-02-04 10:54:18 -05:00
9ade941de1 web_backend: Sync with Citra implementation
While porting https://github.com/citra-emu/citra/pull/7347, I noticed the code of yuzu was not up-to-date with the implementation from Citra.
2024-02-04 16:51:52 +01:00
4cccbe7989 Merge pull request #12892 from liamwhite/serialization-stuff
cmif_serialization: enforce const for references
2024-02-04 09:48:33 -05:00
5eb5c96750 nvnflinger: release buffers before presentation sleep 2024-02-03 17:14:43 -05:00
5da55cbac9 Merge pull request #12901 from Kelebek1/timezone_firmware_fix
Fix firmware timezone boot load check.
2024-02-03 11:10:30 -05:00
81cc4df1f9 Merge pull request #12895 from german77/files
service: fs: Skip non user id folders
2024-02-03 11:10:24 -05:00
25f3d358b1 Merge pull request #12877 from german77/npad-fixed
service: hid: Multiple fixes
2024-02-03 11:10:14 -05:00
a3c8bb251d Merge pull request #12852 from Calinou/multiplayer-color-player-counts
Color player counts in the multiplayer public lobby list
2024-02-03 11:10:00 -05:00
327533be1f Merge pull request #12851 from Calinou/multiplayer-persist-filters
Persist filters in multiplayer public lobby list
2024-02-03 11:09:51 -05:00
61ea2115c7 Merge pull request #12850 from Calinou/multiplayer-add-hotkeys
Add hotkeys for multiplayer actions
2024-02-03 11:09:41 -05:00
108a72ea8a Fix firmware timezone boot load check. 2024-02-03 15:21:10 +00:00
fb3ef957bb service: fs: Skip non user id folders 2024-02-02 13:25:38 -06:00
78f72b3bf5 cmif_serialization: enforce const for references 2024-02-02 09:32:10 -05:00
6baf965777 Merge pull request #12857 from liamwhite/const
service: use const references for input raw data
2024-02-02 15:10:46 +01:00
3f86b339f3 Merge pull request #12845 from liamwhite/notif
notif: rewrite for new IPC
2024-02-02 15:09:57 +01:00
32d38a5df6 Merge pull request #12887 from abouvier/cmake-vulkan-headers
cmake: use vulkan-headers config file
2024-02-02 09:09:02 -05:00
3ac46aeced Merge pull request #12885 from Moonlacer/eclipse-fix
structured_control_flow: Add Samsung Proprietary Driver ID to Reorder Pass
2024-02-02 09:08:54 -05:00
58cf2ee1f9 Merge pull request #12761 from liamwhite/mp-composite
video_core: rewrite presentation for layer composition
2024-02-02 15:08:06 +01:00
c74b5f9ee6 cmake: use vulkan-headers config file 2024-02-02 04:38:56 +01:00
11a8ef6640 Clang Fix 2024-02-01 18:15:21 -06:00
b51b47e707 Add Samsung Proprietary Driver ID to Reorder Pass
For RDNA-based Samsung Xclipse GPUs
2024-02-01 17:53:26 -06:00
35e3c68028 service: use const references for input raw data 2024-02-01 12:57:54 -05:00
f740d8b9be MemoryManager: Reduce the page table size based on last big page address. 2024-02-01 13:00:36 +01:00
2c421a7046 hardware_composer: implement speed limit extensions 2024-01-31 11:27:21 -05:00
a595e9e8a7 nvnflinger/gpu: implement layer stack composition 2024-01-31 11:27:21 -05:00
10cf058518 renderer_opengl: implement layer stack composition 2024-01-31 11:27:21 -05:00
9bdf09bd76 renderer_vulkan: implement layer stack composition 2024-01-31 11:27:21 -05:00
d4de04584f renderer_opengl: split up blit screen resources into antialias and window adapt passes 2024-01-31 11:27:21 -05:00
dd2918efd8 renderer_opengl: move out ownership of FSR resources 2024-01-31 11:27:21 -05:00
2ed9586130 renderer_vulkan: convert FSR to graphics pipeline 2024-01-31 11:27:21 -05:00
b78900e956 renderer_opengl: move out FSR shader source construction 2024-01-31 11:27:20 -05:00
60ee29aac3 renderer_opengl: split out FXAA 2024-01-31 11:27:20 -05:00
b90eff4bc6 renderer_opengl: split out SMAA 2024-01-31 11:27:20 -05:00
0c2e5b64c9 renderer_vulkan: split up blit screen resources into separate antialias and window adapt passes 2024-01-31 11:27:20 -05:00
9568b310be renderer_vulkan: isolate FXAA from blit screen 2024-01-31 11:27:20 -05:00
2b1dd3bef5 renderer_opengl: isolate core presentation code 2024-01-31 11:27:20 -05:00
453091f611 video_core: consistently account for resolution scaling when rendering 2024-01-31 11:27:20 -05:00
80de01a5b4 video_core: simplify accelerated surface fetch and crop handling between APIs 2024-01-31 11:27:20 -05:00
442aad9b27 Persist filters in multiplayer public lobby list
After connecting to a room, the chosen filter text, "Games I Own",
"Hide Empty Rooms" and "Hide Full Rooms" values are persisted
to configuration so they are preserved across restarts.

This makes it easier to rejoin a room if you regularly play the same
game, or after a crash.
2024-01-30 17:40:29 +01:00
8e0f97ac96 Color player counts in the multiplayer public lobby list
- Full lobbies have their player count displayed in red.
- Lobbies with one slot left have their player count displayed in orange.
- Empty lobbies have their player count grayed out.
2024-01-30 17:38:21 +01:00
345d691328 Add hotkeys for multiplayer actions
Default shortcuts were chosen as to be intuitive (use the first letter
of the action, or the second word's first letter) and work on all
types of keyboards. The hotkeys can be used while playing a game too,
as they are application-wide.
2024-01-30 01:32:14 +01:00
41149d061d notif: rewrite for new IPC 2024-01-29 11:56:32 -05:00
395 changed files with 11008 additions and 7570 deletions

View File

@ -0,0 +1,21 @@
#!/bin/bash -ex
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
export NDK_CCACHE="$(which ccache)"
ccache -s
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
base64 --decode <<< "${EA_PLAY_ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}"
export ANDROID_KEY_ALIAS="${PLAY_ANDROID_KEY_ALIAS}"
export ANDROID_KEYSTORE_PASS="${PLAY_ANDROID_KEYSTORE_PASS}"
export SERVICE_ACCOUNT_KEY_PATH="${GITHUB_WORKSPACE}/sa.json"
base64 --decode <<< "${EA_SERVICE_ACCOUNT_KEY_B64}" > "${SERVICE_ACCOUNT_KEY_PATH}"
./gradlew "publishEaReleaseBundle"
ccache -s
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
rm "${ANDROID_KEYSTORE_FILE}"
fi

View File

@ -0,0 +1,21 @@
#!/bin/bash -ex
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
export NDK_CCACHE="$(which ccache)"
ccache -s
export ANDROID_KEYSTORE_FILE="${GITHUB_WORKSPACE}/ks.jks"
base64 --decode <<< "${MAINLINE_PLAY_ANDROID_KEYSTORE_B64}" > "${ANDROID_KEYSTORE_FILE}"
export ANDROID_KEY_ALIAS="${PLAY_ANDROID_KEY_ALIAS}"
export ANDROID_KEYSTORE_PASS="${PLAY_ANDROID_KEYSTORE_PASS}"
export SERVICE_ACCOUNT_KEY_PATH="${GITHUB_WORKSPACE}/sa.json"
base64 --decode <<< "${MAINLINE_SERVICE_ACCOUNT_KEY_B64}" > "${SERVICE_ACCOUNT_KEY_PATH}"
./gradlew "publishMainlineReleaseBundle"
ccache -s
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
rm "${ANDROID_KEYSTORE_FILE}"
fi

View File

@ -0,0 +1,66 @@
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: yuzu-android-ea-play-release
on:
workflow_dispatch:
inputs:
release-track:
description: 'Play store release track (internal/alpha/beta/production)'
required: true
default: 'alpha'
jobs:
android:
runs-on: ubuntu-latest
if: ${{ github.repository == 'yuzu-emu/yuzu' }}
steps:
- uses: actions/checkout@v3
name: Checkout
with:
fetch-depth: 0
submodules: true
token: ${{ secrets.ALT_GITHUB_TOKEN }}
- run: npm install execa@5
- uses: actions/github-script@v5
name: 'Merge and publish Android EA changes'
env:
ALT_GITHUB_TOKEN: ${{ secrets.ALT_GITHUB_TOKEN }}
BUILD_EA: true
with:
script: |
const execa = require("execa");
const mergebot = require('./.github/workflows/android-merge.js').mergebot;
process.chdir('${{ github.workspace }}');
mergebot(github, context, execa);
- name: Get tag name
run: echo "GIT_TAG_NAME=$(cat tag-name.txt)" >> $GITHUB_ENV
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y ccache apksigner glslang-dev glslang-tools
- name: Build
run: ./.ci/scripts/android/eabuild.sh
env:
EA_PLAY_ANDROID_KEYSTORE_B64: ${{ secrets.PLAY_ANDROID_KEYSTORE_B64 }}
PLAY_ANDROID_KEY_ALIAS: ${{ secrets.PLAY_ANDROID_KEY_ALIAS }}
PLAY_ANDROID_KEYSTORE_PASS: ${{ secrets.PLAY_ANDROID_KEYSTORE_PASS }}
EA_SERVICE_ACCOUNT_KEY_B64: ${{ secrets.EA_SERVICE_ACCOUNT_KEY_B64 }}
STORE_TRACK: ${{ github.event.inputs.release-track }}
AUTO_VERSIONED: true
BUILD_EA: true
- name: Create release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ env.EA_TAG_NAME }}
name: ${{ env.EA_TAG_NAME }}
draft: false
prerelease: false
repository: yuzu/yuzu-android
token: ${{ secrets.ALT_GITHUB_TOKEN }}

View File

@ -0,0 +1,59 @@
# SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: yuzu-android-mainline-play-release
on:
workflow_dispatch:
inputs:
release-tag:
description: 'Tag # from yuzu-android that you want to build and publish'
required: true
default: '200'
release-track:
description: 'Play store release track (internal/alpha/beta/production)'
required: true
default: 'alpha'
jobs:
android:
runs-on: ubuntu-latest
if: ${{ github.repository == 'yuzu-emu/yuzu' }}
steps:
- uses: actions/checkout@v3
name: Checkout
with:
fetch-depth: 0
submodules: true
token: ${{ secrets.ALT_GITHUB_TOKEN }}
- run: npm install execa@5
- uses: actions/github-script@v5
name: 'Pull mainline tag'
env:
MAINLINE_TAG: ${{ github.event.inputs.release-tag }}
with:
script: |
const execa = require("execa");
const mergebot = require('./.github/workflows/android-merge.js').getMainlineTag;
process.chdir('${{ github.workspace }}');
mergebot(execa);
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y ccache apksigner glslang-dev glslang-tools
- name: Build
run: |
echo "GIT_TAG_NAME=android-${{ github.event.inputs.releast-tag }}" >> $GITHUB_ENV
./.ci/scripts/android/mainlinebuild.sh
env:
MAINLINE_PLAY_ANDROID_KEYSTORE_B64: ${{ secrets.PLAY_ANDROID_KEYSTORE_B64 }}
PLAY_ANDROID_KEY_ALIAS: ${{ secrets.PLAY_ANDROID_KEY_ALIAS }}
PLAY_ANDROID_KEYSTORE_PASS: ${{ secrets.PLAY_ANDROID_KEYSTORE_PASS }}
SERVICE_ACCOUNT_KEY_B64: ${{ secrets.MAINLINE_SERVICE_ACCOUNT_KEY_B64 }}
STORE_TRACK: ${{ github.event.inputs.release-track }}
AUTO_VERSIONED: true

View File

@ -6,9 +6,12 @@
const fs = require("fs"); const fs = require("fs");
// which label to check for changes // which label to check for changes
const CHANGE_LABEL = 'android-merge'; const CHANGE_LABEL_MAINLINE = 'android-merge';
const CHANGE_LABEL_EA = 'android-ea-merge';
// how far back in time should we consider the changes are "recent"? (default: 24 hours) // how far back in time should we consider the changes are "recent"? (default: 24 hours)
const DETECTION_TIME_FRAME = (parseInt(process.env.DETECTION_TIME_FRAME)) || (24 * 3600 * 1000); const DETECTION_TIME_FRAME = (parseInt(process.env.DETECTION_TIME_FRAME)) || (24 * 3600 * 1000);
const BUILD_EA = process.env.BUILD_EA == 'true';
const MAINLINE_TAG = process.env.MAINLINE_TAG;
async function checkBaseChanges(github) { async function checkBaseChanges(github) {
// query the commit date of the latest commit on this branch // query the commit date of the latest commit on this branch
@ -40,20 +43,7 @@ async function checkBaseChanges(github) {
async function checkAndroidChanges(github) { async function checkAndroidChanges(github) {
if (checkBaseChanges(github)) return true; if (checkBaseChanges(github)) return true;
const query = `query($owner:String!, $name:String!, $label:String!) { const pulls = getPulls(github, false);
repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) {
nodes { number headRepository { pushedAt } }
}
}
}`;
const variables = {
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL,
};
const result = await github.graphql(query, variables);
const pulls = result.repository.pullRequests.nodes;
for (let i = 0; i < pulls.length; i++) { for (let i = 0; i < pulls.length; i++) {
let pull = pulls[i]; let pull = pulls[i];
if (new Date() - new Date(pull.headRepository.pushedAt) <= DETECTION_TIME_FRAME) { if (new Date() - new Date(pull.headRepository.pushedAt) <= DETECTION_TIME_FRAME) {
@ -83,7 +73,13 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
}; };
const tags = await github.graphql(query, variables); const tags = await github.graphql(query, variables);
const tagList = tags.repository.refs.nodes; const tagList = tags.repository.refs.nodes;
const lastTag = tagList[0] ? tagList[0].name : 'dummy-0'; let lastTag = 'android-1';
for (let i = 0; i < tagList.length; ++i) {
if (tagList[i].name.includes('android-')) {
lastTag = tagList[i].name;
break;
}
}
const tagNumber = /\w+-(\d+)/.exec(lastTag)[1] | 0; const tagNumber = /\w+-(\d+)/.exec(lastTag)[1] | 0;
const channel = repo.split('-')[1]; const channel = repo.split('-')[1];
const newTag = `${channel}-${tagNumber + 1}`; const newTag = `${channel}-${tagNumber + 1}`;
@ -101,6 +97,48 @@ async function tagAndPush(github, owner, repo, execa, commit=false) {
console.info('Successfully pushed new changes.'); console.info('Successfully pushed new changes.');
} }
async function tagAndPushEA(github, owner, repo, execa) {
let altToken = process.env.ALT_GITHUB_TOKEN;
if (!altToken) {
throw `Please set ALT_GITHUB_TOKEN environment variable. This token should have write access to ${owner}/${repo}.`;
}
const query = `query ($owner:String!, $name:String!) {
repository(name:$name, owner:$owner) {
refs(refPrefix: "refs/tags/", orderBy: {field: TAG_COMMIT_DATE, direction: DESC}, first: 10) {
nodes { name }
}
}
}`;
const variables = {
owner: owner,
name: repo,
};
const tags = await github.graphql(query, variables);
const tagList = tags.repository.refs.nodes;
let lastTag = 'ea-1';
for (let i = 0; i < tagList.length; ++i) {
if (tagList[i].name.includes('ea-')) {
lastTag = tagList[i].name;
break;
}
}
const tagNumber = /\w+-(\d+)/.exec(lastTag)[1] | 0;
const newTag = `ea-${tagNumber + 1}`;
console.log(`New tag: ${newTag}`);
console.info('Pushing tags to GitHub ...');
await execa("git", ["remote", "add", "android", "https://github.com/yuzu-emu/yuzu-android.git"]);
await execa("git", ["fetch", "android"]);
await execa("git", ['tag', newTag]);
await execa("git", ['push', 'android', `${newTag}`]);
fs.writeFile('tag-name.txt', newTag, (err) => {
if (err) throw 'Could not write tag name to file!'
})
console.info('Successfully pushed new changes.');
}
async function generateReadme(pulls, context, mergeResults, execa) { async function generateReadme(pulls, context, mergeResults, execa) {
let baseUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/`; let baseUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/`;
let output = let output =
@ -202,10 +240,7 @@ async function resetBranch(execa) {
} }
} }
async function mergebot(github, context, execa) { async function getPulls(github) {
// Reset our local copy of master to what appears on yuzu-emu/yuzu - master
await resetBranch(execa);
const query = `query ($owner:String!, $name:String!, $label:String!) { const query = `query ($owner:String!, $name:String!, $label:String!) {
repository(name:$name, owner:$owner) { repository(name:$name, owner:$owner) {
pullRequests(labels: [$label], states: OPEN, first: 100) { pullRequests(labels: [$label], states: OPEN, first: 100) {
@ -215,13 +250,49 @@ async function mergebot(github, context, execa) {
} }
} }
}`; }`;
const variables = { const mainlineVariables = {
owner: 'yuzu-emu', owner: 'yuzu-emu',
name: 'yuzu', name: 'yuzu',
label: CHANGE_LABEL, label: CHANGE_LABEL_MAINLINE,
}; };
const result = await github.graphql(query, variables); const mainlineResult = await github.graphql(query, mainlineVariables);
const pulls = result.repository.pullRequests.nodes; const pulls = mainlineResult.repository.pullRequests.nodes;
if (BUILD_EA) {
const eaVariables = {
owner: 'yuzu-emu',
name: 'yuzu',
label: CHANGE_LABEL_EA,
};
const eaResult = await github.graphql(query, eaVariables);
const eaPulls = eaResult.repository.pullRequests.nodes;
return pulls.concat(eaPulls);
}
return pulls;
}
async function getMainlineTag(execa) {
console.log(`::group::Getting mainline tag android-${MAINLINE_TAG}`);
let hasFailed = false;
try {
await execa("git", ["remote", "add", "mainline", "https://github.com/yuzu-emu/yuzu-android.git"]);
await execa("git", ["fetch", "mainline", "--tags"]);
await execa("git", ["checkout", `tags/android-${MAINLINE_TAG}`]);
await execa("git", ["submodule", "update", "--init", "--recursive"]);
} catch (err) {
console.log('::error title=Failed pull tag');
hasFailed = true;
}
console.log("::endgroup::");
if (hasFailed) {
throw 'Failed pull mainline tag. Aborting!';
}
}
async function mergebot(github, context, execa) {
// Reset our local copy of master to what appears on yuzu-emu/yuzu - master
await resetBranch(execa);
const pulls = await getPulls(github);
let displayList = []; let displayList = [];
for (let i = 0; i < pulls.length; i++) { for (let i = 0; i < pulls.length; i++) {
let pull = pulls[i]; let pull = pulls[i];
@ -231,11 +302,17 @@ async function mergebot(github, context, execa) {
console.table(displayList); console.table(displayList);
await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa); await fetchPullRequests(pulls, "https://github.com/yuzu-emu/yuzu", execa);
const mergeResults = await mergePullRequests(pulls, execa); const mergeResults = await mergePullRequests(pulls, execa);
if (BUILD_EA) {
await tagAndPushEA(github, 'yuzu-emu', `yuzu-android`, execa);
} else {
await generateReadme(pulls, context, mergeResults, execa); await generateReadme(pulls, context, mergeResults, execa);
await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true); await tagAndPush(github, 'yuzu-emu', `yuzu-android`, execa, true);
} }
}
module.exports.mergebot = mergebot; module.exports.mergebot = mergebot;
module.exports.checkAndroidChanges = checkAndroidChanges; module.exports.checkAndroidChanges = checkAndroidChanges;
module.exports.tagAndPush = tagAndPush; module.exports.tagAndPush = tagAndPush;
module.exports.checkBaseChanges = checkBaseChanges; module.exports.checkBaseChanges = checkBaseChanges;
module.exports.getMainlineTag = getMainlineTag;

View File

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project # SPDX-FileCopyrightText: 2024 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
name: yuzu-android-publish name: yuzu-android-publish
@ -16,7 +16,7 @@ on:
jobs: jobs:
android: android:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu-android' }} if: ${{ github.event.inputs.android != 'false' && github.repository == 'yuzu-emu/yuzu' }}
steps: steps:
# this checkout is required to make sure the GitHub Actions scripts are available # this checkout is required to make sure the GitHub Actions scripts are available
- uses: actions/checkout@v3 - uses: actions/checkout@v3

View File

@ -307,7 +307,7 @@ find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED) find_package(zstd 1.5 REQUIRED)
if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS) if (NOT YUZU_USE_EXTERNAL_VULKAN_HEADERS)
find_package(Vulkan 1.3.274 REQUIRED) find_package(VulkanHeaders 1.3.274 REQUIRED)
endif() endif()
if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES) if (NOT YUZU_USE_EXTERNAL_VULKAN_UTILITY_LIBRARIES)

View File

@ -11,3 +11,4 @@ type = QT
file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml file_filter = ../../src/android/app/src/main/res/values-<lang>/strings.xml
source_file = ../../src/android/app/src/main/res/values/strings.xml source_file = ../../src/android/app/src/main/res/values/strings.xml
type = ANDROID type = ANDROID
lang_map = ja_JP:ja, ko_KR:ko, pt_BR:pt-rBR, pt_PT:pt-rPT, ru_RU:ru, vi_VN:vi, zh_CN:zh-rCN, zh_TW:zh-rTW

View File

@ -3,8 +3,8 @@
import android.annotation.SuppressLint import android.annotation.SuppressLint
import kotlin.collections.setOf import kotlin.collections.setOf
import org.jetbrains.kotlin.konan.properties.Properties
import org.jlleitschuh.gradle.ktlint.reporter.ReporterType import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
import com.github.triplet.gradle.androidpublisher.ReleaseStatus
plugins { plugins {
id("com.android.application") id("com.android.application")
@ -13,6 +13,7 @@ plugins {
kotlin("plugin.serialization") version "1.9.20" kotlin("plugin.serialization") version "1.9.20"
id("androidx.navigation.safeargs.kotlin") id("androidx.navigation.safeargs.kotlin")
id("org.jlleitschuh.gradle.ktlint") version "11.4.0" id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
id("com.github.triplet.play") version "3.8.6"
} }
/** /**
@ -58,15 +59,7 @@ android {
targetSdk = 34 targetSdk = 34
versionName = getGitVersion() versionName = getGitVersion()
// If you want to use autoVersion for the versionCode, create a property in local.properties versionCode = if (System.getenv("AUTO_VERSIONED") == "true") {
// named "autoVersioned" and set it to "true"
val properties = Properties()
val versionProperty = try {
properties.load(project.rootProject.file("local.properties").inputStream())
properties.getProperty("autoVersioned") ?: ""
} catch (e: Exception) { "" }
versionCode = if (versionProperty == "true") {
autoVersion autoVersion
} else { } else {
1 1
@ -221,6 +214,15 @@ ktlint {
} }
} }
play {
val keyPath = System.getenv("SERVICE_ACCOUNT_KEY_PATH")
if (keyPath != null) {
serviceAccountCredentials.set(File(keyPath))
}
track.set(System.getenv("STORE_TRACK") ?: "internal")
releaseStatus.set(ReleaseStatus.COMPLETED)
}
dependencies { dependencies {
implementation("androidx.core:core-ktx:1.12.0") implementation("androidx.core:core-ktx:1.12.0")
implementation("androidx.appcompat:appcompat:1.6.1") implementation("androidx.appcompat:appcompat:1.6.1")
@ -257,12 +259,18 @@ fun runGitCommand(command: List<String>): String {
} }
fun getGitVersion(): String { fun getGitVersion(): String {
val gitVersion = runGitCommand(
listOf(
"git",
"describe",
"--always",
"--long"
)
).replace(Regex("(-0)?-[^-]+$"), "")
val versionName = if (System.getenv("GITHUB_ACTIONS") != null) { val versionName = if (System.getenv("GITHUB_ACTIONS") != null) {
val gitTag = System.getenv("GIT_TAG_NAME") ?: "" System.getenv("GIT_TAG_NAME") ?: gitVersion
gitTag
} else { } else {
runGitCommand(listOf("git", "describe", "--always", "--long")) gitVersion
.replace(Regex("(-0)?-[^-]+$"), "")
} }
return versionName.ifEmpty { "0.0" } return versionName.ifEmpty { "0.0" }
} }

View File

@ -12,8 +12,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
<uses-feature android:name="android.hardware.vulkan.version" android:version="0x401000" android:required="true" /> <uses-feature android:name="android.hardware.vulkan.version" android:version="0x401000" android:required="true" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<uses-permission android:name="android.permission.NFC" /> <uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
@ -80,10 +78,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
android:resource="@xml/nfc_tech_filter" /> android:resource="@xml/nfc_tech_filter" />
</activity> </activity>
<service android:name="org.yuzu.yuzu_emu.utils.ForegroundService" android:foregroundServiceType="specialUse">
<property android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE" android:value="Keep emulation running in background"/>
</service>
<provider <provider
android:name=".features.DocumentProvider" android:name=".features.DocumentProvider"
android:authorities="${applicationId}.user" android:authorities="${applicationId}.user"

View File

@ -17,17 +17,6 @@ fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
class YuzuApplication : Application() { class YuzuApplication : Application() {
private fun createNotificationChannels() { private fun createNotificationChannels() {
val emulationChannel = NotificationChannel(
getString(R.string.emulation_notification_channel_id),
getString(R.string.emulation_notification_channel_name),
NotificationManager.IMPORTANCE_LOW
)
emulationChannel.description = getString(
R.string.emulation_notification_channel_description
)
emulationChannel.setSound(null, null)
emulationChannel.vibrationPattern = null
val noticeChannel = NotificationChannel( val noticeChannel = NotificationChannel(
getString(R.string.notice_notification_channel_id), getString(R.string.notice_notification_channel_id),
getString(R.string.notice_notification_channel_name), getString(R.string.notice_notification_channel_name),
@ -39,7 +28,6 @@ class YuzuApplication : Application() {
// Register the channel with the system; you can't change the importance // Register the channel with the system; you can't change the importance
// or other notification behaviors after this // or other notification behaviors after this
val notificationManager = getSystemService(NotificationManager::class.java) val notificationManager = getSystemService(NotificationManager::class.java)
notificationManager.createNotificationChannel(emulationChannel)
notificationManager.createNotificationChannel(noticeChannel) notificationManager.createNotificationChannel(noticeChannel)
} }

View File

@ -4,7 +4,6 @@
package org.yuzu.yuzu_emu.activities package org.yuzu.yuzu_emu.activities
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.app.PendingIntent import android.app.PendingIntent
import android.app.PictureInPictureParams import android.app.PictureInPictureParams
import android.app.RemoteAction import android.app.RemoteAction
@ -45,7 +44,6 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.EmulationViewModel import org.yuzu.yuzu_emu.model.EmulationViewModel
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.MemoryUtil import org.yuzu.yuzu_emu.utils.MemoryUtil
@ -74,11 +72,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
private val emulationViewModel: EmulationViewModel by viewModels() private val emulationViewModel: EmulationViewModel by viewModels()
override fun onDestroy() {
stopForegroundService(this)
super.onDestroy()
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
Log.gameLaunched = true Log.gameLaunched = true
ThemeHelper.setTheme(this) ThemeHelper.setTheme(this)
@ -125,10 +118,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
.apply() .apply()
} }
} }
// Start a foreground service to prevent the app from getting killed in the background
val startIntent = Intent(this, ForegroundService::class.java)
startForegroundService(startIntent)
} }
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
@ -481,12 +470,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
activity.startActivity(launcher) activity.startActivity(launcher)
} }
fun stopForegroundService(activity: Activity) {
val startIntent = Intent(activity, ForegroundService::class.java)
startIntent.action = ForegroundService.ACTION_STOP
activity.startForegroundService(startIntent)
}
private fun areCoordinatesOutside(view: View?, x: Float, y: Float): Boolean { private fun areCoordinatesOutside(view: View?, x: Float, y: Float): Boolean {
if (view == null) { if (view == null) {
return true return true

View File

@ -25,7 +25,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
HAPTIC_FEEDBACK("haptic_feedback"), HAPTIC_FEEDBACK("haptic_feedback"),
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"), SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
SHOW_INPUT_OVERLAY("show_input_overlay"), SHOW_INPUT_OVERLAY("show_input_overlay"),
TOUCHSCREEN("touchscreen"); TOUCHSCREEN("touchscreen"),
SHOW_THERMAL_OVERLAY("show_thermal_overlay");
override fun getBoolean(needsGlobal: Boolean): Boolean = override fun getBoolean(needsGlobal: Boolean): Boolean =
NativeConfig.getBoolean(key, needsGlobal) NativeConfig.getBoolean(key, needsGlobal)

View File

@ -8,7 +8,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
@ -27,6 +26,7 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.SettingsViewModel import org.yuzu.yuzu_emu.model.SettingsViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class SettingsFragment : Fragment() { class SettingsFragment : Fragment() {
private lateinit var presenter: SettingsFragmentPresenter private lateinit var presenter: SettingsFragmentPresenter
@ -125,18 +125,10 @@ class SettingsFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpSettingsList = binding.listSettings.layoutParams as MarginLayoutParams binding.listSettings.updateMargins(left = leftInsets, right = rightInsets)
mlpSettingsList.leftMargin = leftInsets binding.listSettings.updatePadding(bottom = barInsets.bottom)
mlpSettingsList.rightMargin = rightInsets
binding.listSettings.layoutParams = mlpSettingsList
binding.listSettings.updatePadding(
bottom = barInsets.bottom
)
val mlpAppBar = binding.appbarSettings.layoutParams as MarginLayoutParams binding.appbarSettings.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.leftMargin = leftInsets
mlpAppBar.rightMargin = rightInsets
binding.appbarSettings.layoutParams = mlpAppBar
windowInsets windowInsets
} }
} }

View File

@ -13,7 +13,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.Toast import android.widget.Toast
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
@ -26,6 +25,7 @@ import org.yuzu.yuzu_emu.BuildConfig
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentAboutBinding import org.yuzu.yuzu_emu.databinding.FragmentAboutBinding
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class AboutFragment : Fragment() { class AboutFragment : Fragment() {
private var _binding: FragmentAboutBinding? = null private var _binding: FragmentAboutBinding? = null
@ -114,15 +114,8 @@ class AboutFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpToolbar = binding.toolbarAbout.layoutParams as MarginLayoutParams binding.toolbarAbout.updateMargins(left = leftInsets, right = rightInsets)
mlpToolbar.leftMargin = leftInsets binding.scrollAbout.updateMargins(left = leftInsets, right = rightInsets)
mlpToolbar.rightMargin = rightInsets
binding.toolbarAbout.layoutParams = mlpToolbar
val mlpScrollAbout = binding.scrollAbout.layoutParams as MarginLayoutParams
mlpScrollAbout.leftMargin = leftInsets
mlpScrollAbout.rightMargin = rightInsets
binding.scrollAbout.layoutParams = mlpScrollAbout
binding.contentAbout.updatePadding(bottom = barInsets.bottom) binding.contentAbout.updatePadding(bottom = barInsets.bottom)

View File

@ -31,6 +31,7 @@ import org.yuzu.yuzu_emu.model.AddonViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.AddonUtil import org.yuzu.yuzu_emu.utils.AddonUtil
import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo import org.yuzu.yuzu_emu.utils.FileUtil.copyFilesTo
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.File import java.io.File
class AddonsFragment : Fragment() { class AddonsFragment : Fragment() {
@ -202,27 +203,19 @@ class AddonsFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpToolbar = binding.toolbarAddons.layoutParams as ViewGroup.MarginLayoutParams binding.toolbarAddons.updateMargins(left = leftInsets, right = rightInsets)
mlpToolbar.leftMargin = leftInsets binding.listAddons.updateMargins(left = leftInsets, right = rightInsets)
mlpToolbar.rightMargin = rightInsets
binding.toolbarAddons.layoutParams = mlpToolbar
val mlpAddonsList = binding.listAddons.layoutParams as ViewGroup.MarginLayoutParams
mlpAddonsList.leftMargin = leftInsets
mlpAddonsList.rightMargin = rightInsets
binding.listAddons.layoutParams = mlpAddonsList
binding.listAddons.updatePadding( binding.listAddons.updatePadding(
bottom = barInsets.bottom + bottom = barInsets.bottom +
resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab)
) )
val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab) val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab)
val mlpFab = binding.buttonInstall.updateMargins(
binding.buttonInstall.layoutParams as ViewGroup.MarginLayoutParams left = leftInsets + fabSpacing,
mlpFab.leftMargin = leftInsets + fabSpacing right = rightInsets + fabSpacing,
mlpFab.rightMargin = rightInsets + fabSpacing bottom = barInsets.bottom + fabSpacing
mlpFab.bottomMargin = barInsets.bottom + fabSpacing )
binding.buttonInstall.layoutParams = mlpFab
windowInsets windowInsets
} }

View File

@ -21,6 +21,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentAppletLauncherBinding
import org.yuzu.yuzu_emu.model.Applet import org.yuzu.yuzu_emu.model.Applet
import org.yuzu.yuzu_emu.model.AppletInfo import org.yuzu.yuzu_emu.model.AppletInfo
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class AppletLauncherFragment : Fragment() { class AppletLauncherFragment : Fragment() {
private var _binding: FragmentAppletLauncherBinding? = null private var _binding: FragmentAppletLauncherBinding? = null
@ -95,16 +96,8 @@ class AppletLauncherFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.toolbarApplets.layoutParams as ViewGroup.MarginLayoutParams binding.toolbarApplets.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.leftMargin = leftInsets binding.listApplets.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.rightMargin = rightInsets
binding.toolbarApplets.layoutParams = mlpAppBar
val mlpListApplets =
binding.listApplets.layoutParams as ViewGroup.MarginLayoutParams
mlpListApplets.leftMargin = leftInsets
mlpListApplets.rightMargin = rightInsets
binding.listApplets.layoutParams = mlpListApplets
binding.listApplets.updatePadding(bottom = barInsets.bottom) binding.listApplets.updatePadding(bottom = barInsets.bottom)

View File

@ -34,6 +34,7 @@ import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
@ -141,23 +142,15 @@ class DriverManagerFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.toolbarDrivers.layoutParams as ViewGroup.MarginLayoutParams binding.toolbarDrivers.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.leftMargin = leftInsets binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.rightMargin = rightInsets
binding.toolbarDrivers.layoutParams = mlpAppBar
val mlplistDrivers = binding.listDrivers.layoutParams as ViewGroup.MarginLayoutParams
mlplistDrivers.leftMargin = leftInsets
mlplistDrivers.rightMargin = rightInsets
binding.listDrivers.layoutParams = mlplistDrivers
val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab) val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab)
val mlpFab = binding.buttonInstall.updateMargins(
binding.buttonInstall.layoutParams as ViewGroup.MarginLayoutParams left = leftInsets + fabSpacing,
mlpFab.leftMargin = leftInsets + fabSpacing right = rightInsets + fabSpacing,
mlpFab.rightMargin = rightInsets + fabSpacing bottom = barInsets.bottom + fabSpacing
mlpFab.bottomMargin = barInsets.bottom + fabSpacing )
binding.buttonInstall.layoutParams = mlpFab
binding.listDrivers.updatePadding( binding.listDrivers.updatePadding(
bottom = barInsets.bottom + bottom = barInsets.bottom +

View File

@ -19,6 +19,7 @@ import com.google.android.material.transition.MaterialSharedAxis
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentEarlyAccessBinding import org.yuzu.yuzu_emu.databinding.FragmentEarlyAccessBinding
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class EarlyAccessFragment : Fragment() { class EarlyAccessFragment : Fragment() {
private var _binding: FragmentEarlyAccessBinding? = null private var _binding: FragmentEarlyAccessBinding? = null
@ -73,10 +74,7 @@ class EarlyAccessFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.appbarEa.layoutParams as ViewGroup.MarginLayoutParams binding.appbarEa.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.leftMargin = leftInsets
mlpAppBar.rightMargin = rightInsets
binding.appbarEa.layoutParams = mlpAppBar
binding.scrollEa.updatePadding( binding.scrollEa.updatePadding(
left = leftInsets, left = leftInsets,

View File

@ -13,6 +13,7 @@ import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.os.PowerManager
import android.os.SystemClock import android.os.SystemClock
import android.view.* import android.view.*
import android.widget.TextView import android.widget.TextView
@ -23,6 +24,7 @@ import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.Insets import androidx.core.graphics.Insets
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
@ -38,7 +40,6 @@ import androidx.window.layout.WindowLayoutInfo
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.slider.Slider import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
@ -64,6 +65,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private lateinit var emulationState: EmulationState private lateinit var emulationState: EmulationState
private var emulationActivity: EmulationActivity? = null private var emulationActivity: EmulationActivity? = null
private var perfStatsUpdater: (() -> Unit)? = null private var perfStatsUpdater: (() -> Unit)? = null
private var thermalStatsUpdater: (() -> Unit)? = null
private var _binding: FragmentEmulationBinding? = null private var _binding: FragmentEmulationBinding? = null
private val binding get() = _binding!! private val binding get() = _binding!!
@ -77,6 +79,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private var isInFoldableLayout = false private var isInFoldableLayout = false
private lateinit var powerManager: PowerManager
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
super.onAttach(context) super.onAttach(context)
if (context is EmulationActivity) { if (context is EmulationActivity) {
@ -102,6 +106,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
updateOrientation() updateOrientation()
powerManager = requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
val intentUri: Uri? = requireActivity().intent.data val intentUri: Uri? = requireActivity().intent.data
var intentGame: Game? = null var intentGame: Game? = null
if (intentUri != null) { if (intentUri != null) {
@ -394,8 +400,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
emulationState.updateSurface() emulationState.updateSurface()
// Setup overlay // Setup overlays
updateShowFpsOverlay() updateShowFpsOverlay()
updateThermalOverlay()
} }
} }
} }
@ -553,6 +560,38 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
} }
} }
private fun updateThermalOverlay() {
if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()) {
thermalStatsUpdater = {
if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
) {
val thermalStatus = when (powerManager.currentThermalStatus) {
PowerManager.THERMAL_STATUS_LIGHT -> "😥"
PowerManager.THERMAL_STATUS_MODERATE -> "🥵"
PowerManager.THERMAL_STATUS_SEVERE -> "🔥"
PowerManager.THERMAL_STATUS_CRITICAL,
PowerManager.THERMAL_STATUS_EMERGENCY,
PowerManager.THERMAL_STATUS_SHUTDOWN -> "☢️"
else -> "🙂"
}
if (_binding != null) {
binding.showThermalsText.text = thermalStatus
}
thermalStatsUpdateHandler.postDelayed(thermalStatsUpdater!!, 1000)
}
}
thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
binding.showThermalsText.visibility = View.VISIBLE
} else {
if (thermalStatsUpdater != null) {
thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
}
binding.showThermalsText.visibility = View.GONE
}
}
@SuppressLint("SourceLockedOrientationActivity") @SuppressLint("SourceLockedOrientationActivity")
private fun updateOrientation() { private fun updateOrientation() {
emulationActivity?.let { emulationActivity?.let {
@ -641,6 +680,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
popup.menu.apply { popup.menu.apply {
findItem(R.id.menu_toggle_fps).isChecked = findItem(R.id.menu_toggle_fps).isChecked =
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean() BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
findItem(R.id.thermal_indicator).isChecked =
BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
findItem(R.id.menu_rel_stick_center).isChecked = findItem(R.id.menu_rel_stick_center).isChecked =
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean() BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean() findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
@ -660,6 +701,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
true true
} }
R.id.thermal_indicator -> {
it.isChecked = !it.isChecked
BooleanSetting.SHOW_THERMAL_OVERLAY.setBoolean(it.isChecked)
updateThermalOverlay()
true
}
R.id.menu_edit_overlay -> { R.id.menu_edit_overlay -> {
binding.drawerLayout.close() binding.drawerLayout.close()
binding.surfaceInputOverlay.requestFocus() binding.surfaceInputOverlay.requestFocus()
@ -850,7 +898,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
right = cutInsets.right right = cutInsets.right
} }
v.setPadding(left, cutInsets.top, right, 0) v.updatePadding(left = left, top = cutInsets.top, right = right)
windowInsets windowInsets
} }
} }
@ -1003,5 +1051,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
companion object { companion object {
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!) private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
private val thermalStatsUpdateHandler = Handler(Looper.myLooper()!!)
} }
} }

View File

@ -26,6 +26,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentFoldersBinding
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class GameFoldersFragment : Fragment() { class GameFoldersFragment : Fragment() {
private var _binding: FragmentFoldersBinding? = null private var _binding: FragmentFoldersBinding? = null
@ -100,23 +101,16 @@ class GameFoldersFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpToolbar = binding.toolbarFolders.layoutParams as ViewGroup.MarginLayoutParams binding.toolbarFolders.updateMargins(left = leftInsets, right = rightInsets)
mlpToolbar.leftMargin = leftInsets
mlpToolbar.rightMargin = rightInsets
binding.toolbarFolders.layoutParams = mlpToolbar
val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab) val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab)
val mlpFab = binding.buttonAdd.updateMargins(
binding.buttonAdd.layoutParams as ViewGroup.MarginLayoutParams left = leftInsets + fabSpacing,
mlpFab.leftMargin = leftInsets + fabSpacing right = rightInsets + fabSpacing,
mlpFab.rightMargin = rightInsets + fabSpacing bottom = barInsets.bottom + fabSpacing
mlpFab.bottomMargin = barInsets.bottom + fabSpacing )
binding.buttonAdd.layoutParams = mlpFab
val mlpListFolders = binding.listFolders.layoutParams as ViewGroup.MarginLayoutParams binding.listFolders.updateMargins(left = leftInsets, right = rightInsets)
mlpListFolders.leftMargin = leftInsets
mlpListFolders.rightMargin = rightInsets
binding.listFolders.layoutParams = mlpListFolders
binding.listFolders.updatePadding( binding.listFolders.updatePadding(
bottom = barInsets.bottom + bottom = barInsets.bottom +

View File

@ -27,6 +27,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentGameInfoBinding
import org.yuzu.yuzu_emu.model.GameVerificationResult import org.yuzu.yuzu_emu.model.GameVerificationResult
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.GameMetadata import org.yuzu.yuzu_emu.utils.GameMetadata
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class GameInfoFragment : Fragment() { class GameInfoFragment : Fragment() {
private var _binding: FragmentGameInfoBinding? = null private var _binding: FragmentGameInfoBinding? = null
@ -122,11 +123,13 @@ class GameInfoFragment : Fragment() {
titleId = R.string.verify_success, titleId = R.string.verify_success,
descriptionId = R.string.operation_completed_successfully descriptionId = R.string.operation_completed_successfully
) )
GameVerificationResult.Failed -> GameVerificationResult.Failed ->
MessageDialogFragment.newInstance( MessageDialogFragment.newInstance(
titleId = R.string.verify_failure, titleId = R.string.verify_failure,
descriptionId = R.string.verify_failure_description descriptionId = R.string.verify_failure_description
) )
GameVerificationResult.NotImplemented -> GameVerificationResult.NotImplemented ->
MessageDialogFragment.newInstance( MessageDialogFragment.newInstance(
titleId = R.string.verify_no_result, titleId = R.string.verify_no_result,
@ -165,15 +168,8 @@ class GameInfoFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpToolbar = binding.toolbarInfo.layoutParams as ViewGroup.MarginLayoutParams binding.toolbarInfo.updateMargins(left = leftInsets, right = rightInsets)
mlpToolbar.leftMargin = leftInsets binding.scrollInfo.updateMargins(left = leftInsets, right = rightInsets)
mlpToolbar.rightMargin = rightInsets
binding.toolbarInfo.layoutParams = mlpToolbar
val mlpScrollAbout = binding.scrollInfo.layoutParams as ViewGroup.MarginLayoutParams
mlpScrollAbout.leftMargin = leftInsets
mlpScrollAbout.rightMargin = rightInsets
binding.scrollInfo.layoutParams = mlpScrollAbout
binding.contentInfo.updatePadding(bottom = barInsets.bottom) binding.contentInfo.updatePadding(bottom = barInsets.bottom)

View File

@ -46,6 +46,7 @@ import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GameIconUtils import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.MemoryUtil import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
@ -320,46 +321,25 @@ class GamePropertiesFragment : Fragment() {
val smallLayout = resources.getBoolean(R.bool.small_layout) val smallLayout = resources.getBoolean(R.bool.small_layout)
if (smallLayout) { if (smallLayout) {
val mlpListAll = binding.listAll.updateMargins(left = leftInsets, right = rightInsets)
binding.listAll.layoutParams as ViewGroup.MarginLayoutParams
mlpListAll.leftMargin = leftInsets
mlpListAll.rightMargin = rightInsets
binding.listAll.layoutParams = mlpListAll
} else { } else {
if (ViewCompat.getLayoutDirection(binding.root) == if (ViewCompat.getLayoutDirection(binding.root) ==
ViewCompat.LAYOUT_DIRECTION_LTR ViewCompat.LAYOUT_DIRECTION_LTR
) { ) {
val mlpListAll = binding.listAll.updateMargins(right = rightInsets)
binding.listAll.layoutParams as ViewGroup.MarginLayoutParams binding.iconLayout!!.updateMargins(top = barInsets.top, left = leftInsets)
mlpListAll.rightMargin = rightInsets
binding.listAll.layoutParams = mlpListAll
val mlpIconLayout =
binding.iconLayout!!.layoutParams as ViewGroup.MarginLayoutParams
mlpIconLayout.topMargin = barInsets.top
mlpIconLayout.leftMargin = leftInsets
binding.iconLayout!!.layoutParams = mlpIconLayout
} else { } else {
val mlpListAll = binding.listAll.updateMargins(left = leftInsets)
binding.listAll.layoutParams as ViewGroup.MarginLayoutParams binding.iconLayout!!.updateMargins(top = barInsets.top, right = rightInsets)
mlpListAll.leftMargin = leftInsets
binding.listAll.layoutParams = mlpListAll
val mlpIconLayout =
binding.iconLayout!!.layoutParams as ViewGroup.MarginLayoutParams
mlpIconLayout.topMargin = barInsets.top
mlpIconLayout.rightMargin = rightInsets
binding.iconLayout!!.layoutParams = mlpIconLayout
} }
} }
val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab) val fabSpacing = resources.getDimensionPixelSize(R.dimen.spacing_fab)
val mlpFab = binding.buttonStart.updateMargins(
binding.buttonStart.layoutParams as ViewGroup.MarginLayoutParams left = leftInsets + fabSpacing,
mlpFab.leftMargin = leftInsets + fabSpacing right = rightInsets + fabSpacing,
mlpFab.rightMargin = rightInsets + fabSpacing bottom = barInsets.bottom + fabSpacing
mlpFab.bottomMargin = barInsets.bottom + fabSpacing )
binding.buttonStart.layoutParams = mlpFab
binding.layoutAll.updatePadding( binding.layoutAll.updatePadding(
top = barInsets.top, top = barInsets.top,

View File

@ -12,7 +12,6 @@ import android.provider.DocumentsContract
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
@ -44,6 +43,7 @@ import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class HomeSettingsFragment : Fragment() { class HomeSettingsFragment : Fragment() {
private var _binding: FragmentHomeSettingsBinding? = null private var _binding: FragmentHomeSettingsBinding? = null
@ -408,10 +408,7 @@ class HomeSettingsFragment : Fragment() {
bottom = barInsets.bottom bottom = barInsets.bottom
) )
val mlpScrollSettings = binding.scrollViewSettings.layoutParams as MarginLayoutParams binding.scrollViewSettings.updateMargins(left = leftInsets, right = rightInsets)
mlpScrollSettings.leftMargin = leftInsets
mlpScrollSettings.rightMargin = rightInsets
binding.scrollViewSettings.layoutParams = mlpScrollSettings
binding.linearLayoutSettings.updatePadding(bottom = spacingNavigation) binding.linearLayoutSettings.updatePadding(bottom = spacingNavigation)

View File

@ -34,6 +34,7 @@ import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.ui.main.MainActivity import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.DirectoryInitialization import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.math.BigInteger import java.math.BigInteger
@ -172,16 +173,8 @@ class InstallableFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.toolbarInstallables.layoutParams as ViewGroup.MarginLayoutParams binding.toolbarInstallables.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.leftMargin = leftInsets binding.listInstallables.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.rightMargin = rightInsets
binding.toolbarInstallables.layoutParams = mlpAppBar
val mlpScrollAbout =
binding.listInstallables.layoutParams as ViewGroup.MarginLayoutParams
mlpScrollAbout.leftMargin = leftInsets
mlpScrollAbout.rightMargin = rightInsets
binding.listInstallables.layoutParams = mlpScrollAbout
binding.listInstallables.updatePadding(bottom = barInsets.bottom) binding.listInstallables.updatePadding(bottom = barInsets.bottom)

View File

@ -7,7 +7,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
@ -22,6 +21,7 @@ import org.yuzu.yuzu_emu.adapters.LicenseAdapter
import org.yuzu.yuzu_emu.databinding.FragmentLicensesBinding import org.yuzu.yuzu_emu.databinding.FragmentLicensesBinding
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.License import org.yuzu.yuzu_emu.model.License
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class LicensesFragment : Fragment() { class LicensesFragment : Fragment() {
private var _binding: FragmentLicensesBinding? = null private var _binding: FragmentLicensesBinding? = null
@ -122,15 +122,8 @@ class LicensesFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpAppBar = binding.appbarLicenses.layoutParams as MarginLayoutParams binding.appbarLicenses.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.leftMargin = leftInsets binding.listLicenses.updateMargins(left = leftInsets, right = rightInsets)
mlpAppBar.rightMargin = rightInsets
binding.appbarLicenses.layoutParams = mlpAppBar
val mlpScrollAbout = binding.listLicenses.layoutParams as MarginLayoutParams
mlpScrollAbout.leftMargin = leftInsets
mlpScrollAbout.rightMargin = rightInsets
binding.listLicenses.layoutParams = mlpScrollAbout
binding.listLicenses.updatePadding(bottom = barInsets.bottom) binding.listLicenses.updatePadding(bottom = barInsets.bottom)

View File

@ -29,6 +29,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.model.SettingsViewModel import org.yuzu.yuzu_emu.model.SettingsViewModel
import org.yuzu.yuzu_emu.utils.NativeConfig import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class SettingsSearchFragment : Fragment() { class SettingsSearchFragment : Fragment() {
private var _binding: FragmentSettingsSearchBinding? = null private var _binding: FragmentSettingsSearchBinding? = null
@ -174,15 +175,14 @@ class SettingsSearchFragment : Fragment() {
bottom = barInsets.bottom bottom = barInsets.bottom
) )
val mlpSettingsList = binding.settingsList.layoutParams as ViewGroup.MarginLayoutParams binding.settingsList.updateMargins(
mlpSettingsList.leftMargin = leftInsets + sideMargin left = leftInsets + sideMargin,
mlpSettingsList.rightMargin = rightInsets + sideMargin right = rightInsets + sideMargin
binding.settingsList.layoutParams = mlpSettingsList )
binding.divider.updateMargins(
val mlpDivider = binding.divider.layoutParams as ViewGroup.MarginLayoutParams left = leftInsets + sideMargin,
mlpDivider.leftMargin = leftInsets + sideMargin right = rightInsets + sideMargin
mlpDivider.rightMargin = rightInsets + sideMargin )
binding.divider.layoutParams = mlpDivider
windowInsets windowInsets
} }

View File

@ -8,7 +8,6 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewGroup.MarginLayoutParams
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
@ -27,6 +26,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class GamesFragment : Fragment() { class GamesFragment : Fragment() {
private var _binding: FragmentGamesBinding? = null private var _binding: FragmentGamesBinding? = null
@ -169,15 +169,16 @@ class GamesFragment : Fragment() {
val leftInsets = barInsets.left + cutoutInsets.left val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right val rightInsets = barInsets.right + cutoutInsets.right
val mlpSwipe = binding.swipeRefresh.layoutParams as MarginLayoutParams val left: Int
val right: Int
if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_LTR) { if (ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_LTR) {
mlpSwipe.leftMargin = leftInsets + spacingNavigationRail left = leftInsets + spacingNavigationRail
mlpSwipe.rightMargin = rightInsets right = rightInsets
} else { } else {
mlpSwipe.leftMargin = leftInsets left = leftInsets
mlpSwipe.rightMargin = rightInsets + spacingNavigationRail right = rightInsets + spacingNavigationRail
} }
binding.swipeRefresh.layoutParams = mlpSwipe binding.swipeRefresh.updateMargins(left = left, right = right)
binding.noticeText.updatePadding(bottom = spacingNavigation) binding.noticeText.updatePadding(bottom = spacingNavigation)

View File

@ -34,7 +34,6 @@ import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.HomeNavigationDirections import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity
import org.yuzu.yuzu_emu.databinding.ActivityMainBinding import org.yuzu.yuzu_emu.databinding.ActivityMainBinding
import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment import org.yuzu.yuzu_emu.fragments.AddGameFolderDialogFragment
@ -177,9 +176,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
} }
} }
// Dismiss previous notifications (should not happen unless a crash occurred)
EmulationActivity.stopForegroundService(this)
setInsets() setInsets()
} }
@ -298,11 +294,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
super.onResume() super.onResume()
} }
override fun onDestroy() {
EmulationActivity.stopForegroundService(this)
super.onDestroy()
}
private fun setInsets() = private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener( ViewCompat.setOnApplyWindowInsetsListener(
binding.root binding.root

View File

@ -1,70 +0,0 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.activities.EmulationActivity
/**
* A service that shows a permanent notification in the background to avoid the app getting
* cleared from memory by the system.
*/
class ForegroundService : Service() {
companion object {
const val EMULATION_RUNNING_NOTIFICATION = 0x1000
const val ACTION_STOP = "stop"
}
private fun showRunningNotification() {
// Intent is used to resume emulation if the notification is clicked
val contentIntent = PendingIntent.getActivity(
this,
0,
Intent(this, EmulationActivity::class.java),
PendingIntent.FLAG_IMMUTABLE
)
val builder =
NotificationCompat.Builder(this, getString(R.string.emulation_notification_channel_id))
.setSmallIcon(R.drawable.ic_stat_notification_logo)
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.emulation_notification_running))
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOngoing(true)
.setVibrate(null)
.setSound(null)
.setContentIntent(contentIntent)
startForeground(EMULATION_RUNNING_NOTIFICATION, builder.build())
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onCreate() {
showRunningNotification()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent == null) {
return START_NOT_STICKY
}
if (intent.action == ACTION_STOP) {
NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION)
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelfResult(startId)
}
return START_STICKY
}
override fun onDestroy() {
NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION)
}
}

View File

@ -4,6 +4,7 @@
package org.yuzu.yuzu_emu.utils package org.yuzu.yuzu_emu.utils
import android.view.View import android.view.View
import android.view.ViewGroup
object ViewUtils { object ViewUtils {
fun showView(view: View, length: Long = 300) { fun showView(view: View, length: Long = 300) {
@ -32,4 +33,28 @@ object ViewUtils {
view.visibility = View.INVISIBLE view.visibility = View.INVISIBLE
}.start() }.start()
} }
fun View.updateMargins(
left: Int = -1,
top: Int = -1,
right: Int = -1,
bottom: Int = -1
) {
val layoutParams = this.layoutParams as ViewGroup.MarginLayoutParams
layoutParams.apply {
if (left != -1) {
leftMargin = left
}
if (top != -1) {
topMargin = top
}
if (right != -1) {
rightMargin = right
}
if (bottom != -1) {
bottomMargin = bottom
}
}
this.layoutParams = layoutParams
}
} }

View File

@ -2,14 +2,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
add_library(yuzu-android SHARED add_library(yuzu-android SHARED
android_common/android_common.cpp
android_common/android_common.h
applets/software_keyboard.cpp
applets/software_keyboard.h
emu_window/emu_window.cpp emu_window/emu_window.cpp
emu_window/emu_window.h emu_window/emu_window.h
id_cache.cpp
id_cache.h
native.cpp native.cpp
native.h native.h
native_config.cpp native_config.cpp

View File

@ -60,6 +60,8 @@ struct Values {
Settings::Category::Overlay}; Settings::Category::Overlay};
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay", Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
Settings::Category::Overlay}; Settings::Category::Overlay};
Settings::Setting<bool> show_thermal_overlay{linkage, false, "show_thermal_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay", Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
Settings::Category::Overlay}; Settings::Category::Overlay};
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay}; Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};

View File

@ -3,6 +3,7 @@
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "common/android/id_cache.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "input_common/drivers/touch_screen.h" #include "input_common/drivers/touch_screen.h"
#include "input_common/drivers/virtual_amiibo.h" #include "input_common/drivers/virtual_amiibo.h"
@ -60,7 +61,8 @@ void EmuWindow_Android::OnRemoveNfcTag() {
void EmuWindow_Android::OnFrameDisplayed() { void EmuWindow_Android::OnFrameDisplayed() {
if (!m_first_frame) { if (!m_first_frame) {
EmulationSession::GetInstance().OnEmulationStarted(); Common::Android::RunJNIOnFiber<void>(
[&](JNIEnv* env) { EmulationSession::GetInstance().OnEmulationStarted(); });
m_first_frame = true; m_first_frame = true;
} }
} }

View File

@ -1,13 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/android/android_common.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/fs_filesystem.h" #include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/patch_manager.h" #include "core/file_sys/patch_manager.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/loader/nro.h" #include "core/loader/nro.h"
#include "jni.h"
#include "jni/android_common/android_common.h"
#include "native.h" #include "native.h"
struct RomMetadata { struct RomMetadata {
@ -79,7 +78,7 @@ extern "C" {
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
GetJString(env, jpath), FileSys::OpenMode::Read); Common::Android::GetJString(env, jpath), FileSys::OpenMode::Read);
if (!file) { if (!file) {
return false; return false;
} }
@ -104,27 +103,31 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return ToJString(env, GetRomMetadata(GetJString(env, jpath)).title); return Common::Android::ToJString(
env, GetRomMetadata(Common::Android::GetJString(env, jpath)).title);
} }
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return ToJString(env, std::to_string(GetRomMetadata(GetJString(env, jpath)).programId)); return Common::Android::ToJString(
env, std::to_string(GetRomMetadata(Common::Android::GetJString(env, jpath)).programId));
} }
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return ToJString(env, GetRomMetadata(GetJString(env, jpath)).developer); return Common::Android::ToJString(
env, GetRomMetadata(Common::Android::GetJString(env, jpath)).developer);
} }
jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj, jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj,
jstring jpath, jboolean jreload) { jstring jpath, jboolean jreload) {
return ToJString(env, GetRomMetadata(GetJString(env, jpath), jreload).version); return Common::Android::ToJString(
env, GetRomMetadata(Common::Android::GetJString(env, jpath), jreload).version);
} }
jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj, jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
auto icon_data = GetRomMetadata(GetJString(env, jpath)).icon; auto icon_data = GetRomMetadata(Common::Android::GetJString(env, jpath)).icon;
jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size())); jbyteArray icon = env->NewByteArray(static_cast<jsize>(icon_data.size()));
env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon),
reinterpret_cast<jbyte*>(icon_data.data())); reinterpret_cast<jbyte*>(icon_data.data()));
@ -133,7 +136,8 @@ jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobje
jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj,
jstring jpath) { jstring jpath) {
return static_cast<jboolean>(GetRomMetadata(GetJString(env, jpath)).isHomebrew); return static_cast<jboolean>(
GetRomMetadata(Common::Android::GetJString(env, jpath)).isHomebrew);
} }
void Java_org_yuzu_yuzu_1emu_utils_GameMetadata_resetMetadata(JNIEnv* env, jobject obj) { void Java_org_yuzu_yuzu_1emu_utils_GameMetadata_resetMetadata(JNIEnv* env, jobject obj) {

View File

@ -20,6 +20,8 @@
#include <frontend_common/content_manager.h> #include <frontend_common/content_manager.h>
#include <jni.h> #include <jni.h>
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/detached_tasks.h" #include "common/detached_tasks.h"
#include "common/dynamic_library.h" #include "common/dynamic_library.h"
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
@ -57,8 +59,6 @@
#include "hid_core/frontend/emulated_controller.h" #include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h" #include "hid_core/hid_core.h"
#include "hid_core/hid_types.h" #include "hid_core/hid_types.h"
#include "jni/android_common/android_common.h"
#include "jni/id_cache.h"
#include "jni/native.h" #include "jni/native.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/renderer_vulkan.h"
@ -228,7 +228,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_vulkan_library); std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, m_vulkan_library);
// Initialize system. // Initialize system.
jauto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>(); jauto android_keyboard = std::make_unique<Common::Android::SoftwareKeyboard::AndroidKeyboard>();
m_software_keyboard = android_keyboard.get(); m_software_keyboard = android_keyboard.get();
m_system.SetShuttingDown(false); m_system.SetShuttingDown(false);
m_system.ApplySettings(); m_system.ApplySettings();
@ -411,37 +411,39 @@ void EmulationSession::OnGamepadDisconnectEvent([[maybe_unused]] int index) {
controller->Disconnect(); controller->Disconnect();
} }
SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() { Common::Android::SoftwareKeyboard::AndroidKeyboard* EmulationSession::SoftwareKeyboard() {
return m_software_keyboard; return m_software_keyboard;
} }
void EmulationSession::LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, void EmulationSession::LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress,
int max) { int max) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = Common::Android::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetDiskCacheProgressClass(), env->CallStaticVoidMethod(Common::Android::GetDiskCacheProgressClass(),
IDCache::GetDiskCacheLoadProgress(), static_cast<jint>(stage), Common::Android::GetDiskCacheLoadProgress(), static_cast<jint>(stage),
static_cast<jint>(progress), static_cast<jint>(max)); static_cast<jint>(progress), static_cast<jint>(max));
} }
void EmulationSession::OnEmulationStarted() { void EmulationSession::OnEmulationStarted() {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = Common::Android::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStarted()); env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(),
Common::Android::GetOnEmulationStarted());
} }
void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) { void EmulationSession::OnEmulationStopped(Core::SystemResultStatus result) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = Common::Android::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnEmulationStopped(), env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(),
static_cast<jint>(result)); Common::Android::GetOnEmulationStopped(), static_cast<jint>(result));
} }
void EmulationSession::ChangeProgram(std::size_t program_index) { void EmulationSession::ChangeProgram(std::size_t program_index) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = Common::Android::GetEnvForThread();
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), IDCache::GetOnProgramChanged(), env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(),
Common::Android::GetOnProgramChanged(),
static_cast<jint>(program_index)); static_cast<jint>(program_index));
} }
u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) { u64 EmulationSession::GetProgramId(JNIEnv* env, jstring jprogramId) {
auto program_id_string = GetJString(env, jprogramId); auto program_id_string = Common::Android::GetJString(env, jprogramId);
try { try {
return std::stoull(program_id_string); return std::stoull(program_id_string);
} catch (...) { } catch (...) {
@ -491,7 +493,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env, jobject
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance, void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env, jobject instance,
[[maybe_unused]] jstring j_directory) { [[maybe_unused]] jstring j_directory) {
Common::FS::SetAppDirectory(GetJString(env, j_directory)); Common::FS::SetAppDirectory(Common::Android::GetJString(env, j_directory));
} }
int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance, int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject instance,
@ -501,21 +503,22 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) { const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod, auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
ToJDouble(env, max), ToJDouble(env, progress)); Common::Android::ToJDouble(env, max),
return GetJBoolean(env, jwasCancelled); Common::Android::ToJDouble(env, progress));
return Common::Android::GetJBoolean(env, jwasCancelled);
}; };
return static_cast<int>( return static_cast<int>(
ContentManager::InstallNSP(EmulationSession::GetInstance().System(), ContentManager::InstallNSP(EmulationSession::GetInstance().System(),
*EmulationSession::GetInstance().System().GetFilesystem(), *EmulationSession::GetInstance().System().GetFilesystem(),
GetJString(env, j_file), callback)); Common::Android::GetJString(env, j_file), callback));
} }
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj, jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId, jstring jprogramId,
jstring jupdatePath) { jstring jupdatePath) {
u64 program_id = EmulationSession::GetProgramId(env, jprogramId); u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
std::string updatePath = GetJString(env, jupdatePath); std::string updatePath = Common::Android::GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
updatePath, FileSys::OpenMode::Read)); updatePath, FileSys::OpenMode::Read));
@ -538,8 +541,10 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(JNIEnv* e
jstring custom_driver_name, jstring custom_driver_name,
jstring file_redirect_dir) { jstring file_redirect_dir) {
EmulationSession::GetInstance().InitializeGpuDriver( EmulationSession::GetInstance().InitializeGpuDriver(
GetJString(env, hook_lib_dir), GetJString(env, custom_driver_dir), Common::Android::GetJString(env, hook_lib_dir),
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir)); Common::Android::GetJString(env, custom_driver_dir),
Common::Android::GetJString(env, custom_driver_name),
Common::Android::GetJString(env, file_redirect_dir));
} }
[[maybe_unused]] static bool CheckKgslPresent() { [[maybe_unused]] static bool CheckKgslPresent() {
@ -566,7 +571,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) { JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) {
const char* file_redirect_dir_{}; const char* file_redirect_dir_{};
int featureFlags{}; int featureFlags{};
std::string hook_lib_dir = GetJString(env, j_hook_lib_dir); std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir);
auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(), auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(),
nullptr, nullptr, file_redirect_dir_, nullptr); nullptr, nullptr, file_redirect_dir_, nullptr);
auto driver_library = std::make_shared<Common::DynamicLibrary>(handle); auto driver_library = std::make_shared<Common::DynamicLibrary>(handle);
@ -587,9 +592,10 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version), fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version),
VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version)); VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version));
jobjectArray j_driver_info = jobjectArray j_driver_info = env->NewObjectArray(
env->NewObjectArray(2, IDCache::GetStringClass(), ToJString(env, version_string)); 2, Common::Android::GetStringClass(), Common::Android::ToJString(env, version_string));
env->SetObjectArrayElement(j_driver_info, 1, ToJString(env, device.GetDriverName())); env->SetObjectArrayElement(j_driver_info, 1,
Common::Android::ToJString(env, device.GetDriverName()));
return j_driver_info; return j_driver_info;
} }
@ -742,15 +748,15 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats(JNIEnv* env, jcl
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuBackend(JNIEnv* env, jclass clazz) { jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCpuBackend(JNIEnv* env, jclass clazz) {
if (Settings::IsNceEnabled()) { if (Settings::IsNceEnabled()) {
return ToJString(env, "NCE"); return Common::Android::ToJString(env, "NCE");
} }
return ToJString(env, "JIT"); return Common::Android::ToJString(env, "JIT");
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject jobj) { jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGpuDriver(JNIEnv* env, jobject jobj) {
return ToJString(env, return Common::Android::ToJString(
EmulationSession::GetInstance().System().GPU().Renderer().GetDeviceVendor()); env, EmulationSession::GetInstance().System().GPU().Renderer().GetDeviceVendor());
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) { void Java_org_yuzu_yuzu_1emu_NativeLibrary_applySettings(JNIEnv* env, jobject jobj) {
@ -764,13 +770,14 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logSettings(JNIEnv* env, jobject jobj
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path, void Java_org_yuzu_yuzu_1emu_NativeLibrary_run(JNIEnv* env, jobject jobj, jstring j_path,
jint j_program_index, jint j_program_index,
jboolean j_frontend_initiated) { jboolean j_frontend_initiated) {
const std::string path = GetJString(env, j_path); const std::string path = Common::Android::GetJString(env, j_path);
const Core::SystemResultStatus result{ const Core::SystemResultStatus result{
RunEmulation(path, j_program_index, j_frontend_initiated)}; RunEmulation(path, j_program_index, j_frontend_initiated)};
if (result != Core::SystemResultStatus::Success) { if (result != Core::SystemResultStatus::Success) {
env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(), env->CallStaticVoidMethod(Common::Android::GetNativeLibraryClass(),
IDCache::GetExitEmulationActivity(), static_cast<int>(result)); Common::Android::GetExitEmulationActivity(),
static_cast<int>(result));
} }
} }
@ -781,7 +788,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo(JNIEnv* env, jclass cla
void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz, void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz,
jstring j_text) { jstring j_text) {
const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text)); const std::u16string input = Common::UTF8ToUTF16(Common::Android::GetJString(env, j_text));
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input); EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
} }
@ -815,16 +822,16 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, j
auto bis_system = auto bis_system =
EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents(); EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents();
if (!bis_system) { if (!bis_system) {
return ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
auto applet_nca = auto applet_nca =
bis_system->GetEntry(static_cast<u64>(jid), FileSys::ContentRecordType::Program); bis_system->GetEntry(static_cast<u64>(jid), FileSys::ContentRecordType::Program);
if (!applet_nca) { if (!applet_nca) {
return ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
return ToJString(env, applet_nca->GetFullPath()); return Common::Android::ToJString(env, applet_nca->GetFullPath());
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz, void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCurrentAppletId(JNIEnv* env, jclass clazz,
@ -857,7 +864,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env,
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj, jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj,
jstring jpath, jstring jpath,
jstring jprogramId) { jstring jprogramId) {
const auto path = GetJString(env, jpath); const auto path = Common::Android::GetJString(env, jpath);
const auto vFile = const auto vFile =
Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path); Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path);
if (vFile == nullptr) { if (vFile == nullptr) {
@ -875,14 +882,15 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
auto patches = pm.GetPatches(update_raw); auto patches = pm.GetPatches(update_raw);
jobjectArray jpatchArray = jobjectArray jpatchArray =
env->NewObjectArray(patches.size(), IDCache::GetPatchClass(), nullptr); env->NewObjectArray(patches.size(), Common::Android::GetPatchClass(), nullptr);
int i = 0; int i = 0;
for (const auto& patch : patches) { for (const auto& patch : patches) {
jobject jpatch = env->NewObject( jobject jpatch = env->NewObject(
IDCache::GetPatchClass(), IDCache::GetPatchConstructor(), patch.enabled, Common::Android::GetPatchClass(), Common::Android::GetPatchConstructor(), patch.enabled,
ToJString(env, patch.name), ToJString(env, patch.version), Common::Android::ToJString(env, patch.name),
static_cast<jint>(patch.type), ToJString(env, std::to_string(patch.program_id)), Common::Android::ToJString(env, patch.version), static_cast<jint>(patch.type),
ToJString(env, std::to_string(patch.title_id))); Common::Android::ToJString(env, std::to_string(patch.program_id)),
Common::Android::ToJString(env, std::to_string(patch.title_id)));
env->SetObjectArrayElement(jpatchArray, i, jpatch); env->SetObjectArrayElement(jpatchArray, i, jpatch);
++i; ++i;
} }
@ -906,7 +914,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj,
jstring jname) { jstring jname) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(), ContentManager::RemoveMod(EmulationSession::GetInstance().System().GetFileSystemController(),
program_id, GetJString(env, jname)); program_id, Common::Android::GetJString(env, jname));
} }
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env,
@ -917,17 +925,18 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEn
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) { const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod, auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
ToJDouble(env, max), ToJDouble(env, progress)); Common::Android::ToJDouble(env, max),
return GetJBoolean(env, jwasCancelled); Common::Android::ToJDouble(env, progress));
return Common::Android::GetJBoolean(env, jwasCancelled);
}; };
auto& session = EmulationSession::GetInstance(); auto& session = EmulationSession::GetInstance();
std::vector<std::string> result = ContentManager::VerifyInstalledContents( std::vector<std::string> result = ContentManager::VerifyInstalledContents(
session.System(), *session.GetContentProvider(), callback); session.System(), *session.GetContentProvider(), callback);
jobjectArray jresult = jobjectArray jresult = env->NewObjectArray(result.size(), Common::Android::GetStringClass(),
env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, "")); Common::Android::ToJString(env, ""));
for (size_t i = 0; i < result.size(); ++i) { for (size_t i = 0; i < result.size(); ++i) {
env->SetObjectArrayElement(jresult, i, ToJString(env, result[i])); env->SetObjectArrayElement(jresult, i, Common::Android::ToJString(env, result[i]));
} }
return jresult; return jresult;
} }
@ -939,19 +948,20 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje
jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) { const auto callback = [env, jcallback, jlambdaInvokeMethod](size_t max, size_t progress) {
auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod, auto jwasCancelled = env->CallObjectMethod(jcallback, jlambdaInvokeMethod,
ToJDouble(env, max), ToJDouble(env, progress)); Common::Android::ToJDouble(env, max),
return GetJBoolean(env, jwasCancelled); Common::Android::ToJDouble(env, progress));
return Common::Android::GetJBoolean(env, jwasCancelled);
}; };
auto& session = EmulationSession::GetInstance(); auto& session = EmulationSession::GetInstance();
return static_cast<jint>( return static_cast<jint>(ContentManager::VerifyGameContents(
ContentManager::VerifyGameContents(session.System(), GetJString(env, jpath), callback)); session.System(), Common::Android::GetJString(env, jpath), callback));
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
jstring jprogramId) { jstring jprogramId) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
if (program_id == 0) { if (program_id == 0) {
return ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
auto& system = EmulationSession::GetInstance().System(); auto& system = EmulationSession::GetInstance().System();
@ -968,7 +978,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject j
const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath( const auto user_save_data_path = FileSys::SaveDataFactory::GetFullPath(
{}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData, {}, vfsNandDir, FileSys::SaveDataSpaceId::NandUser, FileSys::SaveDataType::SaveData,
program_id, user_id->AsU128(), 0); program_id, user_id->AsU128(), 0);
return ToJString(env, user_save_data_path); return Common::Android::ToJString(env, user_save_data_path);
} }
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env, jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIEnv* env,
@ -981,12 +991,13 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDefaultProfileSaveDataRoot(JNIE
const auto user_save_data_root = const auto user_save_data_root =
FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture); FileSys::SaveDataFactory::GetUserGameSaveDataRoot(user_id->AsU128(), jfuture);
return ToJString(env, user_save_data_root); return Common::Android::ToJString(env, user_save_data_root);
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj, void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* env, jobject jobj,
jstring jpath) { jstring jpath) {
EmulationSession::GetInstance().ConfigureFilesystemProvider(GetJString(env, jpath)); EmulationSession::GetInstance().ConfigureFilesystemProvider(
Common::Android::GetJString(env, jpath));
} }
void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) { void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) {

View File

@ -2,13 +2,13 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
#include "common/android/applets/software_keyboard.h"
#include "common/detached_tasks.h" #include "common/detached_tasks.h"
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/registered_cache.h" #include "core/file_sys/registered_cache.h"
#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/acc/profile_manager.h"
#include "core/perf_stats.h" #include "core/perf_stats.h"
#include "frontend_common/content_manager.h" #include "frontend_common/content_manager.h"
#include "jni/applets/software_keyboard.h"
#include "jni/emu_window/emu_window.h" #include "jni/emu_window/emu_window.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
@ -54,7 +54,7 @@ public:
void SetDeviceType([[maybe_unused]] int index, int type); void SetDeviceType([[maybe_unused]] int index, int type);
void OnGamepadConnectEvent([[maybe_unused]] int index); void OnGamepadConnectEvent([[maybe_unused]] int index);
void OnGamepadDisconnectEvent([[maybe_unused]] int index); void OnGamepadDisconnectEvent([[maybe_unused]] int index);
SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard(); Common::Android::SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard();
static void OnEmulationStarted(); static void OnEmulationStarted();
@ -79,7 +79,7 @@ private:
Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized}; Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
std::atomic<bool> m_is_running = false; std::atomic<bool> m_is_running = false;
std::atomic<bool> m_is_paused = false; std::atomic<bool> m_is_paused = false;
SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; Common::Android::SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider; std::unique_ptr<FileSys::ManualContentProvider> m_manual_provider;
int m_applet_id{1}; int m_applet_id{1};

View File

@ -8,11 +8,11 @@
#include "android_config.h" #include "android_config.h"
#include "android_settings.h" #include "android_settings.h"
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "frontend_common/config.h" #include "frontend_common/config.h"
#include "jni/android_common/android_common.h"
#include "jni/id_cache.h"
#include "native.h" #include "native.h"
std::unique_ptr<AndroidConfig> global_config; std::unique_ptr<AndroidConfig> global_config;
@ -20,7 +20,7 @@ std::unique_ptr<AndroidConfig> per_game_config;
template <typename T> template <typename T>
Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) {
auto key = GetJString(env, jkey); auto key = Common::Android::GetJString(env, jkey);
auto basic_setting = Settings::values.linkage.by_key[key]; auto basic_setting = Settings::values.linkage.by_key[key];
if (basic_setting != 0) { if (basic_setting != 0) {
return static_cast<Settings::Setting<T>*>(basic_setting); return static_cast<Settings::Setting<T>*>(basic_setting);
@ -55,7 +55,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_initializePerGameConfig(JNIEnv*
jstring jprogramId, jstring jprogramId,
jstring jfileName) { jstring jfileName) {
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto file_name = GetJString(env, jfileName); auto file_name = Common::Android::GetJString(env, jfileName);
const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id); const auto config_file_name = program_id == 0 ? file_name : fmt::format("{:016X}", program_id);
per_game_config = per_game_config =
std::make_unique<AndroidConfig>(config_file_name, Config::ConfigType::PerGameConfig); std::make_unique<AndroidConfig>(config_file_name, Config::ConfigType::PerGameConfig);
@ -186,9 +186,9 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getString(JNIEnv* env, jobjec
jboolean needGlobal) { jboolean needGlobal) {
auto setting = getSetting<std::string>(env, jkey); auto setting = getSetting<std::string>(env, jkey);
if (setting == nullptr) { if (setting == nullptr) {
return ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
return ToJString(env, setting->GetValue(static_cast<bool>(needGlobal))); return Common::Android::ToJString(env, setting->GetValue(static_cast<bool>(needGlobal)));
} }
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey, void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey,
@ -198,7 +198,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject o
return; return;
} }
setting->SetValue(GetJString(env, value)); setting->SetValue(Common::Android::GetJString(env, value));
} }
jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj,
@ -214,13 +214,13 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getPairedSettingKey(JNIEnv* e
jstring jkey) { jstring jkey) {
auto setting = getSetting<std::string>(env, jkey); auto setting = getSetting<std::string>(env, jkey);
if (setting == nullptr) { if (setting == nullptr) {
return ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
if (setting->PairedSetting() == nullptr) { if (setting->PairedSetting() == nullptr) {
return ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
return ToJString(env, setting->PairedSetting()->GetLabel()); return Common::Android::ToJString(env, setting->PairedSetting()->GetLabel());
} }
jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSwitchable(JNIEnv* env, jobject obj, jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsSwitchable(JNIEnv* env, jobject obj,
@ -262,20 +262,20 @@ jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDefaultToString(JNIEnv* en
jstring jkey) { jstring jkey) {
auto setting = getSetting<std::string>(env, jkey); auto setting = getSetting<std::string>(env, jkey);
if (setting != nullptr) { if (setting != nullptr) {
return ToJString(env, setting->DefaultToString()); return Common::Android::ToJString(env, setting->DefaultToString());
} }
return ToJString(env, ""); return Common::Android::ToJString(env, "");
} }
jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) { jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getGameDirs(JNIEnv* env, jobject obj) {
jclass gameDirClass = IDCache::GetGameDirClass(); jclass gameDirClass = Common::Android::GetGameDirClass();
jmethodID gameDirConstructor = IDCache::GetGameDirConstructor(); jmethodID gameDirConstructor = Common::Android::GetGameDirConstructor();
jobjectArray jgameDirArray = jobjectArray jgameDirArray =
env->NewObjectArray(AndroidSettings::values.game_dirs.size(), gameDirClass, nullptr); env->NewObjectArray(AndroidSettings::values.game_dirs.size(), gameDirClass, nullptr);
for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) { for (size_t i = 0; i < AndroidSettings::values.game_dirs.size(); ++i) {
jobject jgameDir = jobject jgameDir = env->NewObject(
env->NewObject(gameDirClass, gameDirConstructor, gameDirClass, gameDirConstructor,
ToJString(env, AndroidSettings::values.game_dirs[i].path), Common::Android::ToJString(env, AndroidSettings::values.game_dirs[i].path),
static_cast<jboolean>(AndroidSettings::values.game_dirs[i].deep_scan)); static_cast<jboolean>(AndroidSettings::values.game_dirs[i].deep_scan));
env->SetObjectArrayElement(jgameDirArray, i, jgameDir); env->SetObjectArrayElement(jgameDirArray, i, jgameDir);
} }
@ -292,14 +292,14 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGameDirs(JNIEnv* env, jobject
} }
jobject dir = env->GetObjectArrayElement(gameDirs, 0); jobject dir = env->GetObjectArrayElement(gameDirs, 0);
jclass gameDirClass = IDCache::GetGameDirClass(); jclass gameDirClass = Common::Android::GetGameDirClass();
jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;"); jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;");
jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z"); jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z");
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
dir = env->GetObjectArrayElement(gameDirs, i); dir = env->GetObjectArrayElement(gameDirs, i);
jstring juriString = static_cast<jstring>(env->GetObjectField(dir, uriStringField)); jstring juriString = static_cast<jstring>(env->GetObjectField(dir, uriStringField));
jboolean jdeepScanBoolean = env->GetBooleanField(dir, deepScanBooleanField); jboolean jdeepScanBoolean = env->GetBooleanField(dir, deepScanBooleanField);
std::string uriString = GetJString(env, juriString); std::string uriString = Common::Android::GetJString(env, juriString);
AndroidSettings::values.game_dirs.push_back( AndroidSettings::values.game_dirs.push_back(
AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)}); AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)});
} }
@ -307,13 +307,13 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setGameDirs(JNIEnv* env, jobject
void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject obj, void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_addGameDir(JNIEnv* env, jobject obj,
jobject gameDir) { jobject gameDir) {
jclass gameDirClass = IDCache::GetGameDirClass(); jclass gameDirClass = Common::Android::GetGameDirClass();
jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;"); jfieldID uriStringField = env->GetFieldID(gameDirClass, "uriString", "Ljava/lang/String;");
jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z"); jfieldID deepScanBooleanField = env->GetFieldID(gameDirClass, "deepScan", "Z");
jstring juriString = static_cast<jstring>(env->GetObjectField(gameDir, uriStringField)); jstring juriString = static_cast<jstring>(env->GetObjectField(gameDir, uriStringField));
jboolean jdeepScanBoolean = env->GetBooleanField(gameDir, deepScanBooleanField); jboolean jdeepScanBoolean = env->GetBooleanField(gameDir, deepScanBooleanField);
std::string uriString = GetJString(env, juriString); std::string uriString = Common::Android::GetJString(env, juriString);
AndroidSettings::values.game_dirs.push_back( AndroidSettings::values.game_dirs.push_back(
AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)}); AndroidSettings::GameDir{uriString, static_cast<bool>(jdeepScanBoolean)});
} }
@ -323,9 +323,11 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getDisabledAddons(JNIEnv
auto program_id = EmulationSession::GetProgramId(env, jprogramId); auto program_id = EmulationSession::GetProgramId(env, jprogramId);
auto& disabledAddons = Settings::values.disabled_addons[program_id]; auto& disabledAddons = Settings::values.disabled_addons[program_id];
jobjectArray jdisabledAddonsArray = jobjectArray jdisabledAddonsArray =
env->NewObjectArray(disabledAddons.size(), IDCache::GetStringClass(), ToJString(env, "")); env->NewObjectArray(disabledAddons.size(), Common::Android::GetStringClass(),
Common::Android::ToJString(env, ""));
for (size_t i = 0; i < disabledAddons.size(); ++i) { for (size_t i = 0; i < disabledAddons.size(); ++i) {
env->SetObjectArrayElement(jdisabledAddonsArray, i, ToJString(env, disabledAddons[i])); env->SetObjectArrayElement(jdisabledAddonsArray, i,
Common::Android::ToJString(env, disabledAddons[i]));
} }
return jdisabledAddonsArray; return jdisabledAddonsArray;
} }
@ -339,7 +341,7 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setDisabledAddons(JNIEnv* env, j
const int size = env->GetArrayLength(jdisabledAddons); const int size = env->GetArrayLength(jdisabledAddons);
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
auto jaddon = static_cast<jstring>(env->GetObjectArrayElement(jdisabledAddons, i)); auto jaddon = static_cast<jstring>(env->GetObjectArrayElement(jdisabledAddons, i));
disabled_addons.push_back(GetJString(env, jaddon)); disabled_addons.push_back(Common::Android::GetJString(env, jaddon));
} }
Settings::values.disabled_addons[program_id] = disabled_addons; Settings::values.disabled_addons[program_id] = disabled_addons;
} }
@ -348,26 +350,27 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JN
jobject obj) { jobject obj) {
jobjectArray joverlayControlDataArray = jobjectArray joverlayControlDataArray =
env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(), env->NewObjectArray(AndroidSettings::values.overlay_control_data.size(),
IDCache::GetOverlayControlDataClass(), nullptr); Common::Android::GetOverlayControlDataClass(), nullptr);
for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) { for (size_t i = 0; i < AndroidSettings::values.overlay_control_data.size(); ++i) {
const auto& control_data = AndroidSettings::values.overlay_control_data[i]; const auto& control_data = AndroidSettings::values.overlay_control_data[i];
jobject jlandscapePosition = jobject jlandscapePosition =
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(),
ToJDouble(env, control_data.landscape_position.first), Common::Android::ToJDouble(env, control_data.landscape_position.first),
ToJDouble(env, control_data.landscape_position.second)); Common::Android::ToJDouble(env, control_data.landscape_position.second));
jobject jportraitPosition = jobject jportraitPosition =
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(),
ToJDouble(env, control_data.portrait_position.first), Common::Android::ToJDouble(env, control_data.portrait_position.first),
ToJDouble(env, control_data.portrait_position.second)); Common::Android::ToJDouble(env, control_data.portrait_position.second));
jobject jfoldablePosition = jobject jfoldablePosition =
env->NewObject(IDCache::GetPairClass(), IDCache::GetPairConstructor(), env->NewObject(Common::Android::GetPairClass(), Common::Android::GetPairConstructor(),
ToJDouble(env, control_data.foldable_position.first), Common::Android::ToJDouble(env, control_data.foldable_position.first),
ToJDouble(env, control_data.foldable_position.second)); Common::Android::ToJDouble(env, control_data.foldable_position.second));
jobject jcontrolData = env->NewObject( jobject jcontrolData =
IDCache::GetOverlayControlDataClass(), IDCache::GetOverlayControlDataConstructor(), env->NewObject(Common::Android::GetOverlayControlDataClass(),
ToJString(env, control_data.id), control_data.enabled, jlandscapePosition, Common::Android::GetOverlayControlDataConstructor(),
jportraitPosition, jfoldablePosition); Common::Android::ToJString(env, control_data.id), control_data.enabled,
jlandscapePosition, jportraitPosition, jfoldablePosition);
env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData); env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData);
} }
return joverlayControlDataArray; return joverlayControlDataArray;
@ -384,33 +387,41 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData(
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i); jobject joverlayControlData = env->GetObjectArrayElement(joverlayControlDataArray, i);
jstring jidString = static_cast<jstring>( jstring jidString = static_cast<jstring>(env->GetObjectField(
env->GetObjectField(joverlayControlData, IDCache::GetOverlayControlDataIdField())); joverlayControlData, Common::Android::GetOverlayControlDataIdField()));
bool enabled = static_cast<bool>(env->GetBooleanField( bool enabled = static_cast<bool>(env->GetBooleanField(
joverlayControlData, IDCache::GetOverlayControlDataEnabledField())); joverlayControlData, Common::Android::GetOverlayControlDataEnabledField()));
jobject jlandscapePosition = env->GetObjectField( jobject jlandscapePosition = env->GetObjectField(
joverlayControlData, IDCache::GetOverlayControlDataLandscapePositionField()); joverlayControlData, Common::Android::GetOverlayControlDataLandscapePositionField());
std::pair<double, double> landscape_position = std::make_pair( std::pair<double, double> landscape_position = std::make_pair(
GetJDouble(env, env->GetObjectField(jlandscapePosition, IDCache::GetPairFirstField())), Common::Android::GetJDouble(
GetJDouble(env, env, env->GetObjectField(jlandscapePosition, Common::Android::GetPairFirstField())),
env->GetObjectField(jlandscapePosition, IDCache::GetPairSecondField()))); Common::Android::GetJDouble(
env,
env->GetObjectField(jlandscapePosition, Common::Android::GetPairSecondField())));
jobject jportraitPosition = env->GetObjectField( jobject jportraitPosition = env->GetObjectField(
joverlayControlData, IDCache::GetOverlayControlDataPortraitPositionField()); joverlayControlData, Common::Android::GetOverlayControlDataPortraitPositionField());
std::pair<double, double> portrait_position = std::make_pair( std::pair<double, double> portrait_position = std::make_pair(
GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairFirstField())), Common::Android::GetJDouble(
GetJDouble(env, env->GetObjectField(jportraitPosition, IDCache::GetPairSecondField()))); env, env->GetObjectField(jportraitPosition, Common::Android::GetPairFirstField())),
Common::Android::GetJDouble(
env,
env->GetObjectField(jportraitPosition, Common::Android::GetPairSecondField())));
jobject jfoldablePosition = env->GetObjectField( jobject jfoldablePosition = env->GetObjectField(
joverlayControlData, IDCache::GetOverlayControlDataFoldablePositionField()); joverlayControlData, Common::Android::GetOverlayControlDataFoldablePositionField());
std::pair<double, double> foldable_position = std::make_pair( std::pair<double, double> foldable_position = std::make_pair(
GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairFirstField())), Common::Android::GetJDouble(
GetJDouble(env, env->GetObjectField(jfoldablePosition, IDCache::GetPairSecondField()))); env, env->GetObjectField(jfoldablePosition, Common::Android::GetPairFirstField())),
Common::Android::GetJDouble(
env,
env->GetObjectField(jfoldablePosition, Common::Android::GetPairSecondField())));
AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{ AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{
GetJString(env, jidString), enabled, landscape_position, portrait_position, Common::Android::GetJString(env, jidString), enabled, landscape_position,
foldable_position}); portrait_position, foldable_position});
} }
} }

View File

@ -1,31 +1,30 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <common/android/android_common.h>
#include <common/logging/log.h> #include <common/logging/log.h>
#include <jni.h> #include <jni.h>
#include "android_common/android_common.h"
extern "C" { extern "C" {
void Java_org_yuzu_yuzu_1emu_utils_Log_debug(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_debug(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_DEBUG(Frontend, "{}", GetJString(env, jmessage)); LOG_DEBUG(Frontend, "{}", Common::Android::GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_warning(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_warning(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_WARNING(Frontend, "{}", GetJString(env, jmessage)); LOG_WARNING(Frontend, "{}", Common::Android::GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_info(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_info(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_INFO(Frontend, "{}", GetJString(env, jmessage)); LOG_INFO(Frontend, "{}", Common::Android::GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_error(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_error(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_ERROR(Frontend, "{}", GetJString(env, jmessage)); LOG_ERROR(Frontend, "{}", Common::Android::GetJString(env, jmessage));
} }
void Java_org_yuzu_yuzu_1emu_utils_Log_critical(JNIEnv* env, jobject obj, jstring jmessage) { void Java_org_yuzu_yuzu_1emu_utils_Log_critical(JNIEnv* env, jobject obj, jstring jmessage) {
LOG_CRITICAL(Frontend, "{}", GetJString(env, jmessage)); LOG_CRITICAL(Frontend, "{}", Common::Android::GetJString(env, jmessage));
} }
} // extern "C" } // extern "C"

View File

@ -140,6 +140,7 @@
android:id="@+id/overlay_container" android:id="@+id/overlay_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginHorizontal="20dp"
android:fitsSystemWindows="true"> android:fitsSystemWindows="true">
<com.google.android.material.textview.MaterialTextView <com.google.android.material.textview.MaterialTextView
@ -150,7 +151,19 @@
android:layout_gravity="left" android:layout_gravity="left"
android:clickable="false" android:clickable="false"
android:focusable="false" android:focusable="false"
android:paddingHorizontal="20dp" android:textColor="@android:color/white"
android:shadowColor="@android:color/black"
android:shadowRadius="3"
tools:ignore="RtlHardcoded" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/show_thermals_text"
style="@style/TextAppearance.Material3.BodySmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:clickable="false"
android:focusable="false"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:shadowColor="@android:color/black" android:shadowColor="@android:color/black"
android:shadowRadius="3" android:shadowRadius="3"

View File

@ -6,6 +6,11 @@
android:title="@string/emulation_fps_counter" android:title="@string/emulation_fps_counter"
android:checkable="true" /> android:checkable="true" />
<item
android:id="@+id/thermal_indicator"
android:title="@string/emulation_thermal_indicator"
android:checkable="true" />
<item <item
android:id="@+id/menu_edit_overlay" android:id="@+id/menu_edit_overlay"
android:title="@string/emulation_touch_overlay_edit" /> android:title="@string/emulation_touch_overlay_edit" />

View File

@ -1,9 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="emulation_notification_channel_name">المحاكي نشط</string>
<string name="emulation_notification_channel_description">اظهار اشعار دائم عندما يكون المحاكي نشطاً</string>
<string name="emulation_notification_running">يوزو قيد التشغيل</string>
<string name="notice_notification_channel_name">الإشعارات والأخطاء</string> <string name="notice_notification_channel_name">الإشعارات والأخطاء</string>
<string name="notice_notification_channel_description">اظهار اشعار عند حصول اي مشكلة.</string> <string name="notice_notification_channel_description">اظهار اشعار عند حصول اي مشكلة.</string>
<string name="notification_permission_not_granted">لم يتم منح إذن الإشعار</string> <string name="notification_permission_not_granted">لم يتم منح إذن الإشعار</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">ئەم نەرمەکاڵایە یارییەکانی کۆنسۆلی نینتێندۆ سویچ کارپێدەکات. هیچ ناونیشانێکی یاری و کلیلی تێدا نییە..&lt;br /&gt;&lt;br /&gt;پێش ئەوەی دەست پێ بکەیت، تکایە شوێنی فایلی <![CDATA[<b> prod.keys </b>]]> دیاریبکە لە نێو کۆگای ئامێرەکەت.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">زیاتر فێربە</a>]]></string> <string name="app_disclaimer">ئەم نەرمەکاڵایە یارییەکانی کۆنسۆلی نینتێندۆ سویچ کارپێدەکات. هیچ ناونیشانێکی یاری و کلیلی تێدا نییە..&lt;br /&gt;&lt;br /&gt;پێش ئەوەی دەست پێ بکەیت، تکایە شوێنی فایلی <![CDATA[<b> prod.keys </b>]]> دیاریبکە لە نێو کۆگای ئامێرەکەت.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">زیاتر فێربە</a>]]></string>
<string name="emulation_notification_channel_name">ئیمولەیشن کارایە</string>
<string name="emulation_notification_channel_description">ئاگادارکردنەوەیەکی بەردەوام نیشان دەدات کاتێک ئیمولەیشن کاردەکات.</string>
<string name="emulation_notification_running">یوزو کاردەکات</string>
<string name="notice_notification_channel_name">ئاگاداری و هەڵەکان</string> <string name="notice_notification_channel_name">ئاگاداری و هەڵەکان</string>
<string name="notice_notification_channel_description">ئاگادارکردنەوەکان پیشان دەدات کاتێک شتێک بە هەڵەدا دەچێت.</string> <string name="notice_notification_channel_description">ئاگادارکردنەوەکان پیشان دەدات کاتێک شتێک بە هەڵەدا دەچێت.</string>
<string name="notification_permission_not_granted">مۆڵەتی ئاگادارکردنەوە نەدراوە!</string> <string name="notification_permission_not_granted">مۆڵەتی ئاگادارکردنەوە نەدراوە!</string>

View File

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="emulation_notification_channel_name">Emulace je aktivní</string>
<string name="notice_notification_channel_name">Upozornění a chyby</string> <string name="notice_notification_channel_name">Upozornění a chyby</string>
<string name="notice_notification_channel_description">Ukáže oznámení v případě chyby.</string> <string name="notice_notification_channel_description">Ukáže oznámení v případě chyby.</string>
<string name="notification_permission_not_granted">Oznámení nejsou oprávněna!</string> <string name="notification_permission_not_granted">Oznámení nejsou oprávněna!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Diese Software kann Spiele für die Nintendo Switch abspielen. Keine Spiele oder Spielekeys sind enthalten.&lt;br /&gt;&lt;br /&gt;Bevor du beginnst, bitte halte deine <![CDATA[<b> prod.keys </b>]]> auf deinem Gerät bereit. .&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Mehr Infos</a>]]></string> <string name="app_disclaimer">Diese Software kann Spiele für die Nintendo Switch abspielen. Keine Spiele oder Spielekeys sind enthalten.&lt;br /&gt;&lt;br /&gt;Bevor du beginnst, bitte halte deine <![CDATA[<b> prod.keys </b>]]> auf deinem Gerät bereit. .&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Mehr Infos</a>]]></string>
<string name="emulation_notification_channel_name">Emulation ist aktiv</string>
<string name="emulation_notification_channel_description">Zeigt eine dauerhafte Benachrichtigung an, wenn die Emulation läuft.</string>
<string name="emulation_notification_running">yuzu läuft</string>
<string name="notice_notification_channel_name">Hinweise und Fehler</string> <string name="notice_notification_channel_name">Hinweise und Fehler</string>
<string name="notice_notification_channel_description">Zeigt Benachrichtigungen an, wenn etwas schief läuft.</string> <string name="notice_notification_channel_description">Zeigt Benachrichtigungen an, wenn etwas schief läuft.</string>
<string name="notification_permission_not_granted">Berechtigung für Benachrichtigungen nicht erlaubt!</string> <string name="notification_permission_not_granted">Berechtigung für Benachrichtigungen nicht erlaubt!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Este software ejecuta juegos para la videoconsola Nintendo Switch. Los videojuegos o claves no vienen incluidos.&lt;br /&gt;&lt;br /&gt;Antes de empezar, por favor, localice el archivo <![CDATA[<b> prod.keys </b>]]>en el almacenamiento de su dispositivo..&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Saber más</a>]]></string> <string name="app_disclaimer">Este software ejecuta juegos para la videoconsola Nintendo Switch. Los videojuegos o claves no vienen incluidos.&lt;br /&gt;&lt;br /&gt;Antes de empezar, por favor, localice el archivo <![CDATA[<b> prod.keys </b>]]>en el almacenamiento de su dispositivo..&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Saber más</a>]]></string>
<string name="emulation_notification_channel_name">Emulación activa</string>
<string name="emulation_notification_channel_description">Muestra una notificación persistente cuando la emulación está activa.</string>
<string name="emulation_notification_running">yuzu está ejecutándose</string>
<string name="notice_notification_channel_name">Avisos y errores</string> <string name="notice_notification_channel_name">Avisos y errores</string>
<string name="notice_notification_channel_description">Mostrar notificaciones cuándo algo vaya mal.</string> <string name="notice_notification_channel_description">Mostrar notificaciones cuándo algo vaya mal.</string>
<string name="notification_permission_not_granted">¡Permisos de notificación no concedidos!</string> <string name="notification_permission_not_granted">¡Permisos de notificación no concedidos!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Ce logiciel exécutera des jeux pour la console de jeu Nintendo Switch. Aucun jeux ou clés n\'est inclus.&lt;br /&gt;&lt;br /&gt;Avant de commencer, veuillez localiser votre fichier <![CDATA[<b> prod.keys </b>]]> sur le stockage de votre appareil.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">En savoir plus</a>]]></string> <string name="app_disclaimer">Ce logiciel exécutera des jeux pour la console de jeu Nintendo Switch. Aucun jeux ou clés n\'est inclus.&lt;br /&gt;&lt;br /&gt;Avant de commencer, veuillez localiser votre fichier <![CDATA[<b> prod.keys </b>]]> sur le stockage de votre appareil.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">En savoir plus</a>]]></string>
<string name="emulation_notification_channel_name">L\'émulation est active</string>
<string name="emulation_notification_channel_description">Affiche une notification persistante lorsque l\'émulation est en cours d\'exécution.</string>
<string name="emulation_notification_running">yuzu est en cours d\'exécution</string>
<string name="notice_notification_channel_name">Avis et erreurs</string> <string name="notice_notification_channel_name">Avis et erreurs</string>
<string name="notice_notification_channel_description">Affiche des notifications en cas de problème.</string> <string name="notice_notification_channel_description">Affiche des notifications en cas de problème.</string>
<string name="notification_permission_not_granted">Permission de notification non accordée !</string> <string name="notification_permission_not_granted">Permission de notification non accordée !</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">התוכנה תריץ משחקים לקונסולת ה Nintendo Switch. אף משחק או קבצים בעלי זכויות יוצרים נכללים.&lt;br /&gt;&lt;br /&gt; לפני שאת/ה מתחיל בבקשה מצא את קובץ <![CDATA[<b>prod.keys</b>]]> על המכשיר.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">קרא עוד</a>]]></string> <string name="app_disclaimer">התוכנה תריץ משחקים לקונסולת ה Nintendo Switch. אף משחק או קבצים בעלי זכויות יוצרים נכללים.&lt;br /&gt;&lt;br /&gt; לפני שאת/ה מתחיל בבקשה מצא את קובץ <![CDATA[<b>prod.keys</b>]]> על המכשיר.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">קרא עוד</a>]]></string>
<string name="emulation_notification_channel_name">אמולציה פעילה</string>
<string name="emulation_notification_channel_description">מציג התראה מתמשכת כאשר האמולציה פועלת.</string>
<string name="emulation_notification_running">yuzu רץ</string>
<string name="notice_notification_channel_name">התראות ותקלות</string> <string name="notice_notification_channel_name">התראות ותקלות</string>
<string name="notice_notification_channel_description">מציג התראות כאשר משהו הולך לא כשורה.</string> <string name="notice_notification_channel_description">מציג התראות כאשר משהו הולך לא כשורה.</string>
<string name="notification_permission_not_granted">הרשאות התראות לא ניתנה!</string> <string name="notification_permission_not_granted">הרשאות התראות לא ניתנה!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Ez a szoftver Nintendo Switch játékkonzolhoz készült játékokat futtat. Nem tartalmaz játékokat vagy kulcsokat. .&lt;br /&gt;&lt;br /&gt;Mielőtt hozzákezdenél, kérjük, válaszd ki a <![CDATA[<b>prod.keys</b>]]> fájl helyét a készülék tárhelyén&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Tudj meg többet</a>]]></string> <string name="app_disclaimer">Ez a szoftver Nintendo Switch játékkonzolhoz készült játékokat futtat. Nem tartalmaz játékokat vagy kulcsokat. .&lt;br /&gt;&lt;br /&gt;Mielőtt hozzákezdenél, kérjük, válaszd ki a <![CDATA[<b>prod.keys</b>]]> fájl helyét a készülék tárhelyén&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Tudj meg többet</a>]]></string>
<string name="emulation_notification_channel_name">Emuláció aktív</string>
<string name="emulation_notification_channel_description">Állandó értesítést jelenít meg, amíg az emuláció fut.</string>
<string name="emulation_notification_running">A yuzu fut</string>
<string name="notice_notification_channel_name">Megjegyzések és hibák</string> <string name="notice_notification_channel_name">Megjegyzések és hibák</string>
<string name="notice_notification_channel_description">Értesítések megjelenítése, ha valami rosszul sül el.</string> <string name="notice_notification_channel_description">Értesítések megjelenítése, ha valami rosszul sül el.</string>
<string name="notification_permission_not_granted">Nincs engedély az értesítés megjelenítéséhez!</string> <string name="notification_permission_not_granted">Nincs engedély az értesítés megjelenítéséhez!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Questo software permette di giocare ai giochi della console Nintendo Switch. Nessun gioco o chiave è inclusa.&lt;br /&gt;&lt;br /&gt;Prima di iniziare, perfavore individua il file <![CDATA[<b>prod.keys </b>]]> nella memoria del tuo dispositivo.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Scopri di più</a>]]></string> <string name="app_disclaimer">Questo software permette di giocare ai giochi della console Nintendo Switch. Nessun gioco o chiave è inclusa.&lt;br /&gt;&lt;br /&gt;Prima di iniziare, perfavore individua il file <![CDATA[<b>prod.keys </b>]]> nella memoria del tuo dispositivo.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Scopri di più</a>]]></string>
<string name="emulation_notification_channel_name">L\'emulatore è attivo</string>
<string name="emulation_notification_channel_description">Mostra una notifica persistente quando l\'emulatore è in esecuzione.</string>
<string name="emulation_notification_running">yuzu è in esecuzione</string>
<string name="notice_notification_channel_name">Avvisi ed errori</string> <string name="notice_notification_channel_name">Avvisi ed errori</string>
<string name="notice_notification_channel_description">Mostra le notifiche quando qualcosa va storto.</string> <string name="notice_notification_channel_description">Mostra le notifiche quando qualcosa va storto.</string>
<string name="notification_permission_not_granted">Autorizzazione di notifica non concessa!</string> <string name="notification_permission_not_granted">Autorizzazione di notifica non concessa!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">このソフトウェアでは、Nintendo Switchのゲームを実行できます。 ゲームソフトやキーは含まれません。&lt;br /&gt;&lt;br /&gt;事前に、 <![CDATA[<b> prod.keys </b>]]> ファイルをストレージに配置しておいてください。&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">詳細</a>]]></string> <string name="app_disclaimer">このソフトウェアでは、Nintendo Switchのゲームを実行できます。 ゲームソフトやキーは含まれません。&lt;br /&gt;&lt;br /&gt;事前に、 <![CDATA[<b> prod.keys </b>]]> ファイルをストレージに配置しておいてください。&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">詳細</a>]]></string>
<string name="emulation_notification_channel_name">エミュレーションが有効です</string>
<string name="emulation_notification_channel_description">エミュレーションの実行中に常設通知を表示します。</string>
<string name="emulation_notification_running">yuzu は実行中です</string>
<string name="notice_notification_channel_name">通知とエラー</string> <string name="notice_notification_channel_name">通知とエラー</string>
<string name="notice_notification_channel_description">問題の発生時に通知を表示します。</string> <string name="notice_notification_channel_description">問題の発生時に通知を表示します。</string>
<string name="notification_permission_not_granted">通知が許可されていません!</string> <string name="notification_permission_not_granted">通知が許可されていません!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">이 소프트웨어는 Nintendo Switch 게임을 실행합니다. 게임 타이틀이나 키는 포함되어 있지 않습니다.&lt;br /&gt;&lt;br /&gt;시작하기 전에 장치 저장소에서 <![CDATA[<b> prod.keys </b>]]> 파일을 찾아주세요.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">자세히 알아보기</a>]]></string> <string name="app_disclaimer">이 소프트웨어는 Nintendo Switch 게임을 실행합니다. 게임 타이틀이나 키는 포함되어 있지 않습니다.&lt;br /&gt;&lt;br /&gt;시작하기 전에 장치 저장소에서 <![CDATA[<b> prod.keys </b>]]> 파일을 찾아주세요.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">자세히 알아보기</a>]]></string>
<string name="emulation_notification_channel_name">에뮬레이션이 활성화됨</string>
<string name="emulation_notification_channel_description">에뮬레이션이 실행 중일 때 지속적으로 알림을 표시합니다.</string>
<string name="emulation_notification_running">yuzu가 실행 중입니다.</string>
<string name="notice_notification_channel_name">알림 및 오류</string> <string name="notice_notification_channel_name">알림 및 오류</string>
<string name="notice_notification_channel_description">문제가 발생하면 알림을 표시합니다.</string> <string name="notice_notification_channel_description">문제가 발생하면 알림을 표시합니다.</string>
<string name="notification_permission_not_granted">알림 권한이 부여되지 않았습니다!</string> <string name="notification_permission_not_granted">알림 권한이 부여되지 않았습니다!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Denne programvaren vil kjøre spill for Nintendo Switch-spillkonsollen. Ingen spilltitler eller nøkler er inkludert.&lt;br /&gt;&lt;br /&gt;Før du begynner, må du finne <![CDATA[<b> prod.keys </b>]]> filen din på enhetslagringen.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Lær mer</a>]]></string> <string name="app_disclaimer">Denne programvaren vil kjøre spill for Nintendo Switch-spillkonsollen. Ingen spilltitler eller nøkler er inkludert.&lt;br /&gt;&lt;br /&gt;Før du begynner, må du finne <![CDATA[<b> prod.keys </b>]]> filen din på enhetslagringen.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Lær mer</a>]]></string>
<string name="emulation_notification_channel_name">Emulering er aktiv</string>
<string name="emulation_notification_channel_description">Viser et vedvarende varsel når emuleringen kjører.</string>
<string name="emulation_notification_running">Yuzu kjører</string>
<string name="notice_notification_channel_name">Merknader og feil</string> <string name="notice_notification_channel_name">Merknader og feil</string>
<string name="notice_notification_channel_description">Viser varsler når noe går galt.</string> <string name="notice_notification_channel_description">Viser varsler når noe går galt.</string>
<string name="notification_permission_not_granted">Varslingstillatelse ikke gitt!</string> <string name="notification_permission_not_granted">Varslingstillatelse ikke gitt!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">To oprogramowanie umożliwia uruchomienie gier z konsoli Nintendo Switch. Nie zawiera gier ani wymaganych kluczy.&lt;br /&gt;&lt;br /&gt;Zanim zaczniesz, wybierz plik kluczy <![CDATA[<b> prod.keys </b>]]> z katalogu w pamięci masowej.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Dowiedz się więcej</a>]]></string> <string name="app_disclaimer">To oprogramowanie umożliwia uruchomienie gier z konsoli Nintendo Switch. Nie zawiera gier ani wymaganych kluczy.&lt;br /&gt;&lt;br /&gt;Zanim zaczniesz, wybierz plik kluczy <![CDATA[<b> prod.keys </b>]]> z katalogu w pamięci masowej.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Dowiedz się więcej</a>]]></string>
<string name="emulation_notification_channel_name">Emulacja jest uruchomiona</string>
<string name="emulation_notification_channel_description">Pokaż trwałe powiadomienie gdy emulacja jest uruchomiona.</string>
<string name="emulation_notification_running">yuzu jest uruchomiony</string>
<string name="notice_notification_channel_name">Powiadomienia błędy</string> <string name="notice_notification_channel_name">Powiadomienia błędy</string>
<string name="notice_notification_channel_description">Pokaż powiadomienie gdy coś pójdzie źle</string> <string name="notice_notification_channel_description">Pokaż powiadomienie gdy coś pójdzie źle</string>
<string name="notification_permission_not_granted">Nie zezwolono na powiadomienia!</string> <string name="notification_permission_not_granted">Nie zezwolono na powiadomienia!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Este software executa jogos do console Nintendo Switch. Não estão inclusos nem jogos ou chaves.&lt;br /&gt;&lt;br /&gt;Antes de começar, por favor localize o arquivo <![CDATA[<b> prod.keys </b>]]> no armazenamento de seu dispositivo.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Saiba mais</a>]]></string> <string name="app_disclaimer">Este software executa jogos do console Nintendo Switch. Não estão inclusos nem jogos ou chaves.&lt;br /&gt;&lt;br /&gt;Antes de começar, por favor localize o arquivo <![CDATA[<b> prod.keys </b>]]> no armazenamento de seu dispositivo.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Saiba mais</a>]]></string>
<string name="emulation_notification_channel_name">A emulação está Ativa</string>
<string name="emulation_notification_channel_description">Mostra uma notificação permanente enquanto a emulação estiver em andamento.</string>
<string name="emulation_notification_running">O Yuzu está em execução </string>
<string name="notice_notification_channel_name">Notificações e erros</string> <string name="notice_notification_channel_name">Notificações e erros</string>
<string name="notice_notification_channel_description">Mostra notificações quando algo dá errado.</string> <string name="notice_notification_channel_description">Mostra notificações quando algo dá errado.</string>
<string name="notification_permission_not_granted">Acesso às notificações não concedido!</string> <string name="notification_permission_not_granted">Acesso às notificações não concedido!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Este software corre jogos para a consola Nintendo Switch. Não estão incluídas nem jogos ou chaves. &lt;br /&gt;&lt;br /&gt;Antes de começares, por favor localiza o ficheiro <![CDATA[1 prod.keys 1]]> no armazenamento do teu dispositivo.&lt;br /&gt;&lt;br /&gt;<![CDATA[2Learn more2]]></string> <string name="app_disclaimer">Este software corre jogos para a consola Nintendo Switch. Não estão incluídas nem jogos ou chaves. &lt;br /&gt;&lt;br /&gt;Antes de começares, por favor localiza o ficheiro <![CDATA[1 prod.keys 1]]> no armazenamento do teu dispositivo.&lt;br /&gt;&lt;br /&gt;<![CDATA[2Learn more2]]></string>
<string name="emulation_notification_channel_name">Emulação está Ativa</string>
<string name="emulation_notification_channel_description">Mostra uma notificação permanente enquanto a emulação está a correr.</string>
<string name="emulation_notification_running">Yuzu está em execução </string>
<string name="notice_notification_channel_name">Notificações e erros</string> <string name="notice_notification_channel_name">Notificações e erros</string>
<string name="notice_notification_channel_description">Mostra notificações quendo algo corre mal.</string> <string name="notice_notification_channel_description">Mostra notificações quendo algo corre mal.</string>
<string name="notification_permission_not_granted">Permissões de notificação não permitidas </string> <string name="notification_permission_not_granted">Permissões de notificação não permitidas </string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Это программное обеспечение позволяет запускать игры для игровой консоли Nintendo Switch. Мы не предоставляем сами игры или ключи.&lt;br /&gt;&lt;br /&gt;Перед началом работы найдите файл <![CDATA[<b> prod.keys </b>]]> в хранилище устройства..&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Узнать больше</a>]]></string> <string name="app_disclaimer">Это программное обеспечение позволяет запускать игры для игровой консоли Nintendo Switch. Мы не предоставляем сами игры или ключи.&lt;br /&gt;&lt;br /&gt;Перед началом работы найдите файл <![CDATA[<b> prod.keys </b>]]> в хранилище устройства..&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Узнать больше</a>]]></string>
<string name="emulation_notification_channel_name">Эмуляция активна</string>
<string name="emulation_notification_channel_description">Показывает постоянное уведомление, когда запущена эмуляция.</string>
<string name="emulation_notification_running">yuzu запущен</string>
<string name="notice_notification_channel_name">Уведомления и ошибки</string> <string name="notice_notification_channel_name">Уведомления и ошибки</string>
<string name="notice_notification_channel_description">Показывать уведомления, когда что-то пошло не так</string> <string name="notice_notification_channel_description">Показывать уведомления, когда что-то пошло не так</string>
<string name="notification_permission_not_granted">Вы не предоставили разрешение на уведомления!</string> <string name="notification_permission_not_granted">Вы не предоставили разрешение на уведомления!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Це програмне забезпечення дозволяє запускати ігри для ігрової консолі Nintendo Switch. Ми не надаємо самі ігри або ключі.&lt;br /&gt;&lt;br /&gt;Перед початком роботи знайдіть ваш файл <![CDATA[<b> prod.keys </b>]]> у сховищі пристрою.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Дізнатися більше</a>]]></string> <string name="app_disclaimer">Це програмне забезпечення дозволяє запускати ігри для ігрової консолі Nintendo Switch. Ми не надаємо самі ігри або ключі.&lt;br /&gt;&lt;br /&gt;Перед початком роботи знайдіть ваш файл <![CDATA[<b> prod.keys </b>]]> у сховищі пристрою.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Дізнатися більше</a>]]></string>
<string name="emulation_notification_channel_name">Емуляція активна</string>
<string name="emulation_notification_channel_description">Показує постійне сповіщення, коли запущено емуляцію.</string>
<string name="emulation_notification_running">yuzu запущено</string>
<string name="notice_notification_channel_name">Сповіщення та помилки</string> <string name="notice_notification_channel_name">Сповіщення та помилки</string>
<string name="notice_notification_channel_description">Показувати сповіщення, коли щось пішло не так</string> <string name="notice_notification_channel_description">Показувати сповіщення, коли щось пішло не так</string>
<string name="notification_permission_not_granted">Ви не надали дозвіл сповіщень!</string> <string name="notification_permission_not_granted">Ви не надали дозвіл сповіщень!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">Phần mềm này sẽ chạy các game cho máy chơi game Nintendo Switch. Không có title games hoặc keys được bao gồm.&lt;br /&gt;&lt;br /&gt;Trước khi bạn bắt đầu, hãy tìm tập tin <![CDATA[<b> prod.keys </b>]]> trên bộ nhớ thiết bị của bạn.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Tìm hiểu thêm</a>]]></string> <string name="app_disclaimer">Phần mềm này sẽ chạy các game cho máy chơi game Nintendo Switch. Không có title games hoặc keys được bao gồm.&lt;br /&gt;&lt;br /&gt;Trước khi bạn bắt đầu, hãy tìm tập tin <![CDATA[<b> prod.keys </b>]]> trên bộ nhớ thiết bị của bạn.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">Tìm hiểu thêm</a>]]></string>
<string name="emulation_notification_channel_name">Giả lập đang chạy</string>
<string name="emulation_notification_channel_description">Hiển thị thông báo liên tục khi giả lập đang chạy.</string>
<string name="emulation_notification_running">yuzu đang chạy</string>
<string name="notice_notification_channel_name">Thông báo và lỗi</string> <string name="notice_notification_channel_name">Thông báo và lỗi</string>
<string name="notice_notification_channel_description">Hiển thị thông báo khi có sự cố xảy ra.</string> <string name="notice_notification_channel_description">Hiển thị thông báo khi có sự cố xảy ra.</string>
<string name="notification_permission_not_granted">Ứng dụng không được cấp quyền thông báo!</string> <string name="notification_permission_not_granted">Ứng dụng không được cấp quyền thông báo!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">此软件可以运行 Nintendo Switch 游戏,但不包含任何游戏和密钥文件。&lt;br /&gt;&lt;br /&gt;在开始前,请找到放置于设备存储中的 <![CDATA[<b> prod.keys </b>]]> 文件。&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">了解更多</a>]]></string> <string name="app_disclaimer">此软件可以运行 Nintendo Switch 游戏,但不包含任何游戏和密钥文件。&lt;br /&gt;&lt;br /&gt;在开始前,请找到放置于设备存储中的 <![CDATA[<b> prod.keys </b>]]> 文件。&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">了解更多</a>]]></string>
<string name="emulation_notification_channel_name">正在进行模拟</string>
<string name="emulation_notification_channel_description">在模拟运行时显示持久通知。</string>
<string name="emulation_notification_running">yuzu 正在运行</string>
<string name="notice_notification_channel_name">通知及错误提醒</string> <string name="notice_notification_channel_name">通知及错误提醒</string>
<string name="notice_notification_channel_description">当发生错误时显示通知。</string> <string name="notice_notification_channel_description">当发生错误时显示通知。</string>
<string name="notification_permission_not_granted">未授予通知权限!</string> <string name="notification_permission_not_granted">未授予通知权限!</string>

View File

@ -2,9 +2,6 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">此軟體可以執行 Nintendo Switch 主機遊戲,但不包含任何遊戲和金鑰。&lt;br /&gt;&lt;br /&gt;在您開始前,請找到放置於您的裝置儲存空間的 <![CDATA[<b> prod.keys </b>]]> 檔案。&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">深入瞭解</a>]]></string> <string name="app_disclaimer">此軟體可以執行 Nintendo Switch 主機遊戲,但不包含任何遊戲和金鑰。&lt;br /&gt;&lt;br /&gt;在您開始前,請找到放置於您的裝置儲存空間的 <![CDATA[<b> prod.keys </b>]]> 檔案。&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href=\"https://yuzu-emu.org/help/quickstart\">深入瞭解</a>]]></string>
<string name="emulation_notification_channel_name">模擬進行中</string>
<string name="emulation_notification_channel_description">在模擬執行時顯示持續通知。</string>
<string name="emulation_notification_running">yuzu 正在執行</string>
<string name="notice_notification_channel_name">通知和錯誤</string> <string name="notice_notification_channel_name">通知和錯誤</string>
<string name="notice_notification_channel_description">發生錯誤時顯示通知。</string> <string name="notice_notification_channel_description">發生錯誤時顯示通知。</string>
<string name="notification_permission_not_granted">未授予通知權限!</string> <string name="notification_permission_not_granted">未授予通知權限!</string>

View File

@ -4,10 +4,6 @@
<!-- General application strings --> <!-- General application strings -->
<string name="app_name" translatable="false">yuzu</string> <string name="app_name" translatable="false">yuzu</string>
<string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.&lt;br /&gt;&lt;br /&gt;Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href="https://yuzu-emu.org/help/quickstart">Learn more</a>]]></string> <string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.&lt;br /&gt;&lt;br /&gt;Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.&lt;br /&gt;&lt;br /&gt;<![CDATA[<a href="https://yuzu-emu.org/help/quickstart">Learn more</a>]]></string>
<string name="emulation_notification_channel_name">Emulation is Active</string>
<string name="emulation_notification_channel_id" translatable="false">emulationIsActive</string>
<string name="emulation_notification_channel_description">Shows a persistent notification when emulation is running.</string>
<string name="emulation_notification_running">yuzu is running</string>
<string name="notice_notification_channel_name">Notices and errors</string> <string name="notice_notification_channel_name">Notices and errors</string>
<string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string> <string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string>
<string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string> <string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string>
@ -380,6 +376,7 @@
<string name="emulation_exit">Exit emulation</string> <string name="emulation_exit">Exit emulation</string>
<string name="emulation_done">Done</string> <string name="emulation_done">Done</string>
<string name="emulation_fps_counter">FPS counter</string> <string name="emulation_fps_counter">FPS counter</string>
<string name="emulation_thermal_indicator">Thermal indicator</string>
<string name="emulation_toggle_controls">Toggle controls</string> <string name="emulation_toggle_controls">Toggle controls</string>
<string name="emulation_rel_stick_center">Relative stick center</string> <string name="emulation_rel_stick_center">Relative stick center</string>
<string name="emulation_dpad_slide">D-pad slide</string> <string name="emulation_dpad_slide">D-pad slide</string>

View File

@ -107,6 +107,8 @@ add_library(common STATIC
quaternion.h quaternion.h
range_map.h range_map.h
range_mutex.h range_mutex.h
range_sets.h
range_sets.inc
reader_writer_queue.h reader_writer_queue.h
ring_buffer.h ring_buffer.h
${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp ${CMAKE_CURRENT_BINARY_DIR}/scm_rev.cpp
@ -121,6 +123,7 @@ add_library(common STATIC
settings_input.cpp settings_input.cpp
settings_input.h settings_input.h
settings_setting.h settings_setting.h
slot_vector.h
socket_types.h socket_types.h
spin_lock.cpp spin_lock.cpp
spin_lock.h spin_lock.h
@ -179,9 +182,15 @@ endif()
if(ANDROID) if(ANDROID)
target_sources(common target_sources(common
PRIVATE PUBLIC
fs/fs_android.cpp fs/fs_android.cpp
fs/fs_android.h fs/fs_android.h
android/android_common.cpp
android/android_common.h
android/id_cache.cpp
android/id_cache.h
android/applets/software_keyboard.cpp
android/applets/software_keyboard.h
) )
endif() endif()

View File

@ -1,15 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "jni/android_common/android_common.h" #include "android_common.h"
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <jni.h> #include <jni.h>
#include "common/android/id_cache.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "jni/id_cache.h"
namespace Common::Android {
std::string GetJString(JNIEnv* env, jstring jstr) { std::string GetJString(JNIEnv* env, jstring jstr) {
if (!jstr) { if (!jstr) {
@ -18,7 +20,8 @@ std::string GetJString(JNIEnv* env, jstring jstr) {
const jchar* jchars = env->GetStringChars(jstr, nullptr); const jchar* jchars = env->GetStringChars(jstr, nullptr);
const jsize length = env->GetStringLength(jstr); const jsize length = env->GetStringLength(jstr);
const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length); const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars),
static_cast<u32>(length));
const std::string converted_string = Common::UTF16ToUTF8(string_view); const std::string converted_string = Common::UTF16ToUTF8(string_view);
env->ReleaseStringChars(jstr, jchars); env->ReleaseStringChars(jstr, jchars);
@ -36,25 +39,27 @@ jstring ToJString(JNIEnv* env, std::u16string_view str) {
} }
double GetJDouble(JNIEnv* env, jobject jdouble) { double GetJDouble(JNIEnv* env, jobject jdouble) {
return env->GetDoubleField(jdouble, IDCache::GetDoubleValueField()); return env->GetDoubleField(jdouble, GetDoubleValueField());
} }
jobject ToJDouble(JNIEnv* env, double value) { jobject ToJDouble(JNIEnv* env, double value) {
return env->NewObject(IDCache::GetDoubleClass(), IDCache::GetDoubleConstructor(), value); return env->NewObject(GetDoubleClass(), GetDoubleConstructor(), value);
} }
s32 GetJInteger(JNIEnv* env, jobject jinteger) { s32 GetJInteger(JNIEnv* env, jobject jinteger) {
return env->GetIntField(jinteger, IDCache::GetIntegerValueField()); return env->GetIntField(jinteger, GetIntegerValueField());
} }
jobject ToJInteger(JNIEnv* env, s32 value) { jobject ToJInteger(JNIEnv* env, s32 value) {
return env->NewObject(IDCache::GetIntegerClass(), IDCache::GetIntegerConstructor(), value); return env->NewObject(GetIntegerClass(), GetIntegerConstructor(), value);
} }
bool GetJBoolean(JNIEnv* env, jobject jboolean) { bool GetJBoolean(JNIEnv* env, jobject jboolean) {
return env->GetBooleanField(jboolean, IDCache::GetBooleanValueField()); return env->GetBooleanField(jboolean, GetBooleanValueField());
} }
jobject ToJBoolean(JNIEnv* env, bool value) { jobject ToJBoolean(JNIEnv* env, bool value) {
return env->NewObject(IDCache::GetBooleanClass(), IDCache::GetBooleanConstructor(), value); return env->NewObject(GetBooleanClass(), GetBooleanConstructor(), value);
} }
} // namespace Common::Android

View File

@ -8,6 +8,8 @@
#include <jni.h> #include <jni.h>
#include "common/common_types.h" #include "common/common_types.h"
namespace Common::Android {
std::string GetJString(JNIEnv* env, jstring jstr); std::string GetJString(JNIEnv* env, jstring jstr);
jstring ToJString(JNIEnv* env, std::string_view str); jstring ToJString(JNIEnv* env, std::string_view str);
jstring ToJString(JNIEnv* env, std::u16string_view str); jstring ToJString(JNIEnv* env, std::u16string_view str);
@ -20,3 +22,5 @@ jobject ToJInteger(JNIEnv* env, s32 value);
bool GetJBoolean(JNIEnv* env, jobject jboolean); bool GetJBoolean(JNIEnv* env, jobject jboolean);
jobject ToJBoolean(JNIEnv* env, bool value); jobject ToJBoolean(JNIEnv* env, bool value);
} // namespace Common::Android

View File

@ -6,12 +6,12 @@
#include <jni.h> #include <jni.h>
#include "common/android/android_common.h"
#include "common/android/applets/software_keyboard.h"
#include "common/android/id_cache.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "jni/android_common/android_common.h"
#include "jni/applets/software_keyboard.h"
#include "jni/id_cache.h"
static jclass s_software_keyboard_class; static jclass s_software_keyboard_class;
static jclass s_keyboard_config_class; static jclass s_keyboard_config_class;
@ -19,10 +19,10 @@ static jclass s_keyboard_data_class;
static jmethodID s_swkbd_execute_normal; static jmethodID s_swkbd_execute_normal;
static jmethodID s_swkbd_execute_inline; static jmethodID s_swkbd_execute_inline;
namespace SoftwareKeyboard { namespace Common::Android::SoftwareKeyboard {
static jobject ToJKeyboardParams(const Core::Frontend::KeyboardInitializeParameters& config) { static jobject ToJKeyboardParams(const Core::Frontend::KeyboardInitializeParameters& config) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = GetEnvForThread();
jobject object = env->AllocObject(s_keyboard_config_class); jobject object = env->AllocObject(s_keyboard_config_class);
env->SetObjectField(object, env->SetObjectField(object,
@ -78,7 +78,7 @@ static jobject ToJKeyboardParams(const Core::Frontend::KeyboardInitializeParamet
} }
AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobject object) { AndroidKeyboard::ResultData AndroidKeyboard::ResultData::CreateFromFrontend(jobject object) {
JNIEnv* env = IDCache::GetEnvForThread(); JNIEnv* env = GetEnvForThread();
const jstring string = reinterpret_cast<jstring>(env->GetObjectField( const jstring string = reinterpret_cast<jstring>(env->GetObjectField(
object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;"))); object, env->GetFieldID(s_keyboard_data_class, "text", "Ljava/lang/String;")));
return ResultData{GetJString(env, string), return ResultData{GetJString(env, string),
@ -141,7 +141,7 @@ void AndroidKeyboard::ShowNormalKeyboard() const {
// Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber. // Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber.
std::thread([&] { std::thread([&] {
data = ResultData::CreateFromFrontend(IDCache::GetEnvForThread()->CallStaticObjectMethod( data = ResultData::CreateFromFrontend(GetEnvForThread()->CallStaticObjectMethod(
s_software_keyboard_class, s_swkbd_execute_normal, ToJKeyboardParams(parameters))); s_software_keyboard_class, s_swkbd_execute_normal, ToJKeyboardParams(parameters)));
}).join(); }).join();
@ -183,8 +183,8 @@ void AndroidKeyboard::ShowInlineKeyboard(
// Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber. // Pivot to a new thread, as we cannot call GetEnvForThread() from a Fiber.
m_is_inline_active = true; m_is_inline_active = true;
std::thread([&] { std::thread([&] {
IDCache::GetEnvForThread()->CallStaticVoidMethod( GetEnvForThread()->CallStaticVoidMethod(s_software_keyboard_class, s_swkbd_execute_inline,
s_software_keyboard_class, s_swkbd_execute_inline, ToJKeyboardParams(parameters)); ToJKeyboardParams(parameters));
}).join(); }).join();
} }
@ -220,7 +220,7 @@ void AndroidKeyboard::SubmitInlineKeyboardText(std::u16string submitted_text) {
m_current_text += submitted_text; m_current_text += submitted_text;
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text, submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
m_current_text.size()); static_cast<int>(m_current_text.size()));
} }
void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) { void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
@ -242,7 +242,7 @@ void AndroidKeyboard::SubmitInlineKeyboardInput(int key_code) {
case KEYCODE_DEL: case KEYCODE_DEL:
m_current_text.pop_back(); m_current_text.pop_back();
submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text, submit_inline_callback(Service::AM::Frontend::SwkbdReplyType::ChangedString, m_current_text,
m_current_text.size()); static_cast<int>(m_current_text.size()));
break; break;
} }
} }
@ -274,4 +274,4 @@ void CleanupJNI(JNIEnv* env) {
env->DeleteGlobalRef(s_keyboard_data_class); env->DeleteGlobalRef(s_keyboard_data_class);
} }
} // namespace SoftwareKeyboard } // namespace Common::Android::SoftwareKeyboard

View File

@ -7,7 +7,7 @@
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
namespace SoftwareKeyboard { namespace Common::Android::SoftwareKeyboard {
class AndroidKeyboard final : public Core::Frontend::SoftwareKeyboardApplet { class AndroidKeyboard final : public Core::Frontend::SoftwareKeyboardApplet {
public: public:
@ -66,7 +66,7 @@ void InitJNI(JNIEnv* env);
// Should be called in JNI_Unload // Should be called in JNI_Unload
void CleanupJNI(JNIEnv* env); void CleanupJNI(JNIEnv* env);
} // namespace SoftwareKeyboard } // namespace Common::Android::SoftwareKeyboard
// Native function calls // Native function calls
extern "C" { extern "C" {

View File

@ -3,10 +3,10 @@
#include <jni.h> #include <jni.h>
#include "applets/software_keyboard.h"
#include "common/android/id_cache.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/fs/fs_android.h" #include "common/fs/fs_android.h"
#include "jni/applets/software_keyboard.h"
#include "jni/id_cache.h"
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
static JavaVM* s_java_vm; static JavaVM* s_java_vm;
@ -67,7 +67,7 @@ static jfieldID s_boolean_value_field;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6; static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
namespace IDCache { namespace Common::Android {
JNIEnv* GetEnvForThread() { JNIEnv* GetEnvForThread() {
thread_local static struct OwnedEnv { thread_local static struct OwnedEnv {
@ -276,8 +276,6 @@ jfieldID GetBooleanValueField() {
return s_boolean_value_field; return s_boolean_value_field;
} }
} // namespace IDCache
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -393,7 +391,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
Common::FS::Android::RegisterCallbacks(env, s_native_library_class); Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
// Initialize applets // Initialize applets
SoftwareKeyboard::InitJNI(env); Common::Android::SoftwareKeyboard::InitJNI(env);
return JNI_VERSION; return JNI_VERSION;
} }
@ -426,3 +424,5 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
} // namespace Common::Android

View File

@ -3,20 +3,40 @@
#pragma once #pragma once
#include <future>
#include <jni.h> #include <jni.h>
#include "video_core/rasterizer_interface.h" #include "video_core/rasterizer_interface.h"
namespace IDCache { namespace Common::Android {
JNIEnv* GetEnvForThread(); JNIEnv* GetEnvForThread();
/**
* Starts a new thread to run JNI. Intended to be used when you must run JNI from a fiber.
* @tparam T Typename of the return value for the work param
* @param work Lambda that runs JNI code. This function will take care of attaching this thread to
* the JVM
* @return The result from the work lambda param
*/
template <typename T = void>
T RunJNIOnFiber(const std::function<T(JNIEnv*)>& work) {
std::future<T> j_result = std::async(std::launch::async, [&] {
auto env = GetEnvForThread();
return work(env);
});
return j_result.get();
}
jclass GetNativeLibraryClass(); jclass GetNativeLibraryClass();
jclass GetDiskCacheProgressClass(); jclass GetDiskCacheProgressClass();
jclass GetDiskCacheLoadCallbackStageClass(); jclass GetDiskCacheLoadCallbackStageClass();
jclass GetGameDirClass(); jclass GetGameDirClass();
jmethodID GetGameDirConstructor(); jmethodID GetGameDirConstructor();
jmethodID GetExitEmulationActivity();
jmethodID GetDiskCacheLoadProgress(); jmethodID GetDiskCacheLoadProgress();
jmethodID GetExitEmulationActivity();
jmethodID GetOnEmulationStarted(); jmethodID GetOnEmulationStarted();
jmethodID GetOnEmulationStopped(); jmethodID GetOnEmulationStopped();
jmethodID GetOnProgramChanged(); jmethodID GetOnProgramChanged();
@ -65,4 +85,4 @@ jclass GetBooleanClass();
jmethodID GetBooleanConstructor(); jmethodID GetBooleanConstructor();
jfieldID GetBooleanValueField(); jfieldID GetBooleanValueField();
} // namespace IDCache } // namespace Common::Android

View File

@ -1,63 +1,38 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/android/android_common.h"
#include "common/android/id_cache.h"
#include "common/assert.h"
#include "common/fs/fs_android.h" #include "common/fs/fs_android.h"
#include "common/string_util.h" #include "common/string_util.h"
namespace Common::FS::Android { namespace Common::FS::Android {
JNIEnv* GetEnvForThread() {
thread_local static struct OwnedEnv {
OwnedEnv() {
status = g_jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
if (status == JNI_EDETACHED)
g_jvm->AttachCurrentThread(&env, nullptr);
}
~OwnedEnv() {
if (status == JNI_EDETACHED)
g_jvm->DetachCurrentThread();
}
int status;
JNIEnv* env = nullptr;
} owned;
return owned.env;
}
void RegisterCallbacks(JNIEnv* env, jclass clazz) { void RegisterCallbacks(JNIEnv* env, jclass clazz) {
env->GetJavaVM(&g_jvm); env->GetJavaVM(&g_jvm);
native_library = clazz; native_library = clazz;
#define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) \ s_get_parent_directory = env->GetStaticMethodID(native_library, "getParentDirectory",
F(JMethodID, JMethodName, Signature) "(Ljava/lang/String;)Ljava/lang/String;");
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \ s_get_filename = env->GetStaticMethodID(native_library, "getFilename",
F(JMethodID, JMethodName, Signature) "(Ljava/lang/String;)Ljava/lang/String;");
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \ s_get_size = env->GetStaticMethodID(native_library, "getSize", "(Ljava/lang/String;)J");
F(JMethodID, JMethodName, Signature) s_is_directory = env->GetStaticMethodID(native_library, "isDirectory", "(Ljava/lang/String;)Z");
#define F(JMethodID, JMethodName, Signature) \ s_file_exists = env->GetStaticMethodID(native_library, "exists", "(Ljava/lang/String;)Z");
JMethodID = env->GetStaticMethodID(native_library, JMethodName, Signature); s_open_content_uri = env->GetStaticMethodID(native_library, "openContentUri",
ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH) "(Ljava/lang/String;Ljava/lang/String;)I");
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
ANDROID_STORAGE_FUNCTIONS(FS)
#undef F
#undef FS
#undef FR
#undef FH
} }
void UnRegisterCallbacks() { void UnRegisterCallbacks() {
#define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) F(JMethodID) s_get_parent_directory = nullptr;
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) F(JMethodID) s_get_filename = nullptr;
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID)
#define F(JMethodID) JMethodID = nullptr; s_get_size = nullptr;
ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH) s_is_directory = nullptr;
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR) s_file_exists = nullptr;
ANDROID_STORAGE_FUNCTIONS(FS)
#undef F s_open_content_uri = nullptr;
#undef FS
#undef FR
#undef FH
} }
bool IsContentUri(const std::string& path) { bool IsContentUri(const std::string& path) {
@ -69,8 +44,8 @@ bool IsContentUri(const std::string& path) {
return path.find(prefix) == 0; return path.find(prefix) == 0;
} }
int OpenContentUri(const std::string& filepath, OpenMode openmode) { s32 OpenContentUri(const std::string& filepath, OpenMode openmode) {
if (open_content_uri == nullptr) if (s_open_content_uri == nullptr)
return -1; return -1;
const char* mode = ""; const char* mode = "";
@ -82,50 +57,66 @@ int OpenContentUri(const std::string& filepath, OpenMode openmode) {
UNIMPLEMENTED(); UNIMPLEMENTED();
return -1; return -1;
} }
auto env = GetEnvForThread(); auto env = Common::Android::GetEnvForThread();
jstring j_filepath = env->NewStringUTF(filepath.c_str()); jstring j_filepath = Common::Android::ToJString(env, filepath);
jstring j_mode = env->NewStringUTF(mode); jstring j_mode = Common::Android::ToJString(env, mode);
return env->CallStaticIntMethod(native_library, open_content_uri, j_filepath, j_mode); return env->CallStaticIntMethod(native_library, s_open_content_uri, j_filepath, j_mode);
} }
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \ u64 GetSize(const std::string& filepath) {
F(FunctionName, ReturnValue, JMethodID, Caller) if (s_get_size == nullptr) {
#define F(FunctionName, ReturnValue, JMethodID, Caller) \ return 0;
ReturnValue FunctionName(const std::string& filepath) { \ }
if (JMethodID == nullptr) { \ auto env = Common::Android::GetEnvForThread();
return 0; \ return static_cast<u64>(env->CallStaticLongMethod(
} \ native_library, s_get_size,
auto env = GetEnvForThread(); \ Common::Android::ToJString(Common::Android::GetEnvForThread(), filepath)));
jstring j_filepath = env->NewStringUTF(filepath.c_str()); \
return env->Caller(native_library, JMethodID, j_filepath); \
} }
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
#undef F
#undef FR
#define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) \ bool IsDirectory(const std::string& filepath) {
F(FunctionName, JMethodID, Caller) if (s_is_directory == nullptr) {
#define F(FunctionName, JMethodID, Caller) \ return 0;
std::string FunctionName(const std::string& filepath) { \ }
if (JMethodID == nullptr) { \ auto env = Common::Android::GetEnvForThread();
return 0; \ return env->CallStaticBooleanMethod(
} \ native_library, s_is_directory,
auto env = GetEnvForThread(); \ Common::Android::ToJString(Common::Android::GetEnvForThread(), filepath));
jstring j_filepath = env->NewStringUTF(filepath.c_str()); \ }
jstring j_return = \
static_cast<jstring>(env->Caller(native_library, JMethodID, j_filepath)); \ bool Exists(const std::string& filepath) {
if (!j_return) { \ if (s_file_exists == nullptr) {
return {}; \ return 0;
} \ }
const jchar* jchars = env->GetStringChars(j_return, nullptr); \ auto env = Common::Android::GetEnvForThread();
const jsize length = env->GetStringLength(j_return); \ return env->CallStaticBooleanMethod(
const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length); \ native_library, s_file_exists,
const std::string converted_string = Common::UTF16ToUTF8(string_view); \ Common::Android::ToJString(Common::Android::GetEnvForThread(), filepath));
env->ReleaseStringChars(j_return, jchars); \ }
return converted_string; \
std::string GetParentDirectory(const std::string& filepath) {
if (s_get_parent_directory == nullptr) {
return 0;
}
auto env = Common::Android::GetEnvForThread();
jstring j_return = static_cast<jstring>(env->CallStaticObjectMethod(
native_library, s_get_parent_directory, Common::Android::ToJString(env, filepath)));
if (!j_return) {
return {};
}
return Common::Android::GetJString(env, j_return);
}
std::string GetFilename(const std::string& filepath) {
if (s_get_filename == nullptr) {
return 0;
}
auto env = Common::Android::GetEnvForThread();
jstring j_return = static_cast<jstring>(env->CallStaticObjectMethod(
native_library, s_get_filename, Common::Android::ToJString(env, filepath)));
if (!j_return) {
return {};
}
return Common::Android::GetJString(env, j_return);
} }
ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH)
#undef F
#undef FH
} // namespace Common::FS::Android } // namespace Common::FS::Android

View File

@ -7,38 +7,17 @@
#include <vector> #include <vector>
#include <jni.h> #include <jni.h>
#define ANDROID_STORAGE_FUNCTIONS(V) \
V(OpenContentUri, int, (const std::string& filepath, OpenMode openmode), open_content_uri, \
"openContentUri", "(Ljava/lang/String;Ljava/lang/String;)I")
#define ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(V) \
V(GetSize, std::uint64_t, get_size, CallStaticLongMethod, "getSize", "(Ljava/lang/String;)J") \
V(IsDirectory, bool, is_directory, CallStaticBooleanMethod, "isDirectory", \
"(Ljava/lang/String;)Z") \
V(Exists, bool, file_exists, CallStaticBooleanMethod, "exists", "(Ljava/lang/String;)Z")
#define ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(V) \
V(GetParentDirectory, get_parent_directory, CallStaticObjectMethod, "getParentDirectory", \
"(Ljava/lang/String;)Ljava/lang/String;") \
V(GetFilename, get_filename, CallStaticObjectMethod, "getFilename", \
"(Ljava/lang/String;)Ljava/lang/String;")
namespace Common::FS::Android { namespace Common::FS::Android {
static JavaVM* g_jvm = nullptr; static JavaVM* g_jvm = nullptr;
static jclass native_library = nullptr; static jclass native_library = nullptr;
#define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) F(JMethodID) static jmethodID s_get_parent_directory;
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) F(JMethodID) static jmethodID s_get_filename;
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) F(JMethodID) static jmethodID s_get_size;
#define F(JMethodID) static jmethodID JMethodID = nullptr; static jmethodID s_is_directory;
ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH) static jmethodID s_file_exists;
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR) static jmethodID s_open_content_uri;
ANDROID_STORAGE_FUNCTIONS(FS)
#undef F
#undef FS
#undef FR
#undef FH
enum class OpenMode { enum class OpenMode {
Read, Read,
@ -57,24 +36,11 @@ void UnRegisterCallbacks();
bool IsContentUri(const std::string& path); bool IsContentUri(const std::string& path);
#define FS(FunctionName, ReturnValue, Parameters, JMethodID, JMethodName, Signature) \ int OpenContentUri(const std::string& filepath, OpenMode openmode);
F(FunctionName, Parameters, ReturnValue) std::uint64_t GetSize(const std::string& filepath);
#define F(FunctionName, Parameters, ReturnValue) ReturnValue FunctionName Parameters; bool IsDirectory(const std::string& filepath);
ANDROID_STORAGE_FUNCTIONS(FS) bool Exists(const std::string& filepath);
#undef F std::string GetParentDirectory(const std::string& filepath);
#undef FS std::string GetFilename(const std::string& filepath);
#define FR(FunctionName, ReturnValue, JMethodID, Caller, JMethodName, Signature) \
F(FunctionName, ReturnValue)
#define F(FunctionName, ReturnValue) ReturnValue FunctionName(const std::string& filepath);
ANDROID_SINGLE_PATH_DETERMINE_FUNCTIONS(FR)
#undef F
#undef FR
#define FH(FunctionName, JMethodID, Caller, JMethodName, Signature) F(FunctionName)
#define F(FunctionName) std::string FunctionName(const std::string& filepath);
ANDROID_SINGLE_PATH_HELPER_FUNCTIONS(FH)
#undef F
#undef FH
} // namespace Common::FS::Android } // namespace Common::FS::Android

View File

@ -9,6 +9,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <fmt/format.h> #include <fmt/format.h>
#include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
namespace Common { namespace Common {
@ -29,6 +30,8 @@ namespace Common {
template <std::size_t Size, bool le = false> template <std::size_t Size, bool le = false>
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) { [[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
std::array<u8, Size> out{}; std::array<u8, Size> out{};
if constexpr (le) { if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {

73
src/common/range_sets.h Normal file
View File

@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include "common/common_types.h"
namespace Common {
template <typename AddressType>
class RangeSet {
public:
RangeSet();
~RangeSet();
RangeSet(RangeSet const&) = delete;
RangeSet& operator=(RangeSet const&) = delete;
RangeSet(RangeSet&& other);
RangeSet& operator=(RangeSet&& other);
void Add(AddressType base_address, size_t size);
void Subtract(AddressType base_address, size_t size);
void Clear();
bool Empty() const;
template <typename Func>
void ForEach(Func&& func) const;
template <typename Func>
void ForEachInRange(AddressType device_addr, size_t size, Func&& func) const;
private:
struct RangeSetImpl;
std::unique_ptr<RangeSetImpl> m_impl;
};
template <typename AddressType>
class OverlapRangeSet {
public:
OverlapRangeSet();
~OverlapRangeSet();
OverlapRangeSet(OverlapRangeSet const&) = delete;
OverlapRangeSet& operator=(OverlapRangeSet const&) = delete;
OverlapRangeSet(OverlapRangeSet&& other);
OverlapRangeSet& operator=(OverlapRangeSet&& other);
void Add(AddressType base_address, size_t size);
void Subtract(AddressType base_address, size_t size);
template <typename Func>
void Subtract(AddressType base_address, size_t size, Func&& on_delete);
void DeleteAll(AddressType base_address, size_t size);
void Clear();
bool Empty() const;
template <typename Func>
void ForEach(Func&& func) const;
template <typename Func>
void ForEachInRange(AddressType device_addr, size_t size, Func&& func) const;
private:
struct OverlapRangeSetImpl;
std::unique_ptr<OverlapRangeSetImpl> m_impl;
};
} // namespace Common

304
src/common/range_sets.inc Normal file
View File

@ -0,0 +1,304 @@
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <limits>
#include <utility>
#include <boost/icl/interval.hpp>
#include <boost/icl/interval_base_set.hpp>
#include <boost/icl/interval_map.hpp>
#include <boost/icl/interval_set.hpp>
#include <boost/icl/split_interval_map.hpp>
#include <boost/pool/pool.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/pool/poolfwd.hpp>
#include "common/range_sets.h"
namespace Common {
namespace {
template <class T>
using RangeSetsAllocator =
boost::fast_pool_allocator<T, boost::default_user_allocator_new_delete,
boost::details::pool::default_mutex, 1024, 2048>;
}
template <typename AddressType>
struct RangeSet<AddressType>::RangeSetImpl {
using IntervalSet = boost::icl::interval_set<
AddressType, std::less, ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less),
RangeSetsAllocator>;
using IntervalType = typename IntervalSet::interval_type;
RangeSetImpl() = default;
~RangeSetImpl() = default;
void Add(AddressType base_address, size_t size) {
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
m_ranges_set.add(interval);
}
void Subtract(AddressType base_address, size_t size) {
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
m_ranges_set.subtract(interval);
}
template <typename Func>
void ForEach(Func&& func) const {
if (m_ranges_set.empty()) {
return;
}
auto it = m_ranges_set.begin();
auto end_it = m_ranges_set.end();
for (; it != end_it; it++) {
const AddressType inter_addr_end = it->upper();
const AddressType inter_addr = it->lower();
func(inter_addr, inter_addr_end);
}
}
template <typename Func>
void ForEachInRange(AddressType base_addr, size_t size, Func&& func) const {
if (m_ranges_set.empty()) {
return;
}
const AddressType start_address = base_addr;
const AddressType end_address = start_address + size;
const RangeSetImpl::IntervalType search_interval{start_address, end_address};
auto it = m_ranges_set.lower_bound(search_interval);
if (it == m_ranges_set.end()) {
return;
}
auto end_it = m_ranges_set.upper_bound(search_interval);
for (; it != end_it; it++) {
AddressType inter_addr_end = it->upper();
AddressType inter_addr = it->lower();
if (inter_addr_end > end_address) {
inter_addr_end = end_address;
}
if (inter_addr < start_address) {
inter_addr = start_address;
}
func(inter_addr, inter_addr_end);
}
}
IntervalSet m_ranges_set;
};
template <typename AddressType>
struct OverlapRangeSet<AddressType>::OverlapRangeSetImpl {
using IntervalSet = boost::icl::split_interval_map<
AddressType, s32, boost::icl::partial_enricher, std::less, boost::icl::inplace_plus,
boost::icl::inter_section,
ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, AddressType, std::less), RangeSetsAllocator>;
using IntervalType = typename IntervalSet::interval_type;
OverlapRangeSetImpl() = default;
~OverlapRangeSetImpl() = default;
void Add(AddressType base_address, size_t size) {
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
m_split_ranges_set += std::make_pair(interval, 1);
}
template <bool has_on_delete, typename Func>
void Subtract(AddressType base_address, size_t size, s32 amount,
[[maybe_unused]] Func&& on_delete) {
if (m_split_ranges_set.empty()) {
return;
}
AddressType end_address = base_address + static_cast<AddressType>(size);
IntervalType interval{base_address, end_address};
bool any_removals = false;
m_split_ranges_set += std::make_pair(interval, -amount);
do {
any_removals = false;
auto it = m_split_ranges_set.lower_bound(interval);
if (it == m_split_ranges_set.end()) {
return;
}
auto end_it = m_split_ranges_set.upper_bound(interval);
for (; it != end_it; it++) {
if (it->second <= 0) {
if constexpr (has_on_delete) {
if (it->second == 0) {
on_delete(it->first.lower(), it->first.upper());
}
}
any_removals = true;
m_split_ranges_set.erase(it);
break;
}
}
} while (any_removals);
}
template <typename Func>
void ForEach(Func&& func) const {
if (m_split_ranges_set.empty()) {
return;
}
auto it = m_split_ranges_set.begin();
auto end_it = m_split_ranges_set.end();
for (; it != end_it; it++) {
const AddressType inter_addr_end = it->first.upper();
const AddressType inter_addr = it->first.lower();
func(inter_addr, inter_addr_end, it->second);
}
}
template <typename Func>
void ForEachInRange(AddressType base_address, size_t size, Func&& func) const {
if (m_split_ranges_set.empty()) {
return;
}
const AddressType start_address = base_address;
const AddressType end_address = start_address + size;
const OverlapRangeSetImpl::IntervalType search_interval{start_address, end_address};
auto it = m_split_ranges_set.lower_bound(search_interval);
if (it == m_split_ranges_set.end()) {
return;
}
auto end_it = m_split_ranges_set.upper_bound(search_interval);
for (; it != end_it; it++) {
auto& inter = it->first;
AddressType inter_addr_end = inter.upper();
AddressType inter_addr = inter.lower();
if (inter_addr_end > end_address) {
inter_addr_end = end_address;
}
if (inter_addr < start_address) {
inter_addr = start_address;
}
func(inter_addr, inter_addr_end, it->second);
}
}
IntervalSet m_split_ranges_set;
};
template <typename AddressType>
RangeSet<AddressType>::RangeSet() {
m_impl = std::make_unique<RangeSet<AddressType>::RangeSetImpl>();
}
template <typename AddressType>
RangeSet<AddressType>::~RangeSet() = default;
template <typename AddressType>
RangeSet<AddressType>::RangeSet(RangeSet&& other) {
m_impl = std::make_unique<RangeSet<AddressType>::RangeSetImpl>();
m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set);
}
template <typename AddressType>
RangeSet<AddressType>& RangeSet<AddressType>::operator=(RangeSet&& other) {
m_impl->m_ranges_set = std::move(other.m_impl->m_ranges_set);
}
template <typename AddressType>
void RangeSet<AddressType>::Add(AddressType base_address, size_t size) {
m_impl->Add(base_address, size);
}
template <typename AddressType>
void RangeSet<AddressType>::Subtract(AddressType base_address, size_t size) {
m_impl->Subtract(base_address, size);
}
template <typename AddressType>
void RangeSet<AddressType>::Clear() {
m_impl->m_ranges_set.clear();
}
template <typename AddressType>
bool RangeSet<AddressType>::Empty() const {
return m_impl->m_ranges_set.empty();
}
template <typename AddressType>
template <typename Func>
void RangeSet<AddressType>::ForEach(Func&& func) const {
m_impl->ForEach(std::move(func));
}
template <typename AddressType>
template <typename Func>
void RangeSet<AddressType>::ForEachInRange(AddressType base_address, size_t size,
Func&& func) const {
m_impl->ForEachInRange(base_address, size, std::move(func));
}
template <typename AddressType>
OverlapRangeSet<AddressType>::OverlapRangeSet() {
m_impl = std::make_unique<OverlapRangeSet<AddressType>::OverlapRangeSetImpl>();
}
template <typename AddressType>
OverlapRangeSet<AddressType>::~OverlapRangeSet() = default;
template <typename AddressType>
OverlapRangeSet<AddressType>::OverlapRangeSet(OverlapRangeSet&& other) {
m_impl = std::make_unique<OverlapRangeSet<AddressType>::OverlapRangeSetImpl>();
m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set);
}
template <typename AddressType>
OverlapRangeSet<AddressType>& OverlapRangeSet<AddressType>::operator=(OverlapRangeSet&& other) {
m_impl->m_split_ranges_set = std::move(other.m_impl->m_split_ranges_set);
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::Add(AddressType base_address, size_t size) {
m_impl->Add(base_address, size);
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::Subtract(AddressType base_address, size_t size) {
m_impl->template Subtract<false>(base_address, size, 1, [](AddressType, AddressType) {});
}
template <typename AddressType>
template <typename Func>
void OverlapRangeSet<AddressType>::Subtract(AddressType base_address, size_t size,
Func&& on_delete) {
m_impl->template Subtract<true, Func>(base_address, size, 1, std::move(on_delete));
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::DeleteAll(AddressType base_address, size_t size) {
m_impl->template Subtract<false>(base_address, size, std::numeric_limits<s32>::max(),
[](AddressType, AddressType) {});
}
template <typename AddressType>
void OverlapRangeSet<AddressType>::Clear() {
m_impl->m_split_ranges_set.clear();
}
template <typename AddressType>
bool OverlapRangeSet<AddressType>::Empty() const {
return m_impl->m_split_ranges_set.empty();
}
template <typename AddressType>
template <typename Func>
void OverlapRangeSet<AddressType>::ForEach(Func&& func) const {
m_impl->ForEach(func);
}
template <typename AddressType>
template <typename Func>
void OverlapRangeSet<AddressType>::ForEachInRange(AddressType base_address, size_t size,
Func&& func) const {
m_impl->ForEachInRange(base_address, size, std::move(func));
}
} // namespace Common

View File

@ -30,6 +30,7 @@ namespace Settings {
#define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED> #define SETTING(TYPE, RANGED) template class Setting<TYPE, RANGED>
#define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED> #define SWITCHABLE(TYPE, RANGED) template class SwitchableSetting<TYPE, RANGED>
SETTING(AppletMode, false);
SETTING(AudioEngine, false); SETTING(AudioEngine, false);
SETTING(bool, false); SETTING(bool, false);
SETTING(int, false); SETTING(int, false);
@ -215,6 +216,8 @@ const char* TranslateCategory(Category category) {
return "Debugging"; return "Debugging";
case Category::GpuDriver: case Category::GpuDriver:
return "GpuDriver"; return "GpuDriver";
case Category::LibraryApplet:
return "LibraryApplet";
case Category::Miscellaneous: case Category::Miscellaneous:
return "Miscellaneous"; return "Miscellaneous";
case Category::Network: case Category::Network:

View File

@ -133,6 +133,38 @@ struct TouchFromButtonMap {
struct Values { struct Values {
Linkage linkage{}; Linkage linkage{};
// Applet
Setting<AppletMode> cabinet_applet_mode{linkage, AppletMode::LLE, "cabinet_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> controller_applet_mode{linkage, AppletMode::HLE, "controller_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> data_erase_applet_mode{linkage, AppletMode::HLE, "data_erase_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> error_applet_mode{linkage, AppletMode::HLE, "error_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> net_connect_applet_mode{linkage, AppletMode::HLE, "net_connect_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> player_select_applet_mode{
linkage, AppletMode::HLE, "player_select_applet_mode", Category::LibraryApplet};
Setting<AppletMode> swkbd_applet_mode{linkage, AppletMode::LLE, "swkbd_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> mii_edit_applet_mode{linkage, AppletMode::LLE, "mii_edit_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> web_applet_mode{linkage, AppletMode::HLE, "web_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> shop_applet_mode{linkage, AppletMode::HLE, "shop_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> photo_viewer_applet_mode{
linkage, AppletMode::LLE, "photo_viewer_applet_mode", Category::LibraryApplet};
Setting<AppletMode> offline_web_applet_mode{linkage, AppletMode::LLE, "offline_web_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> login_share_applet_mode{linkage, AppletMode::HLE, "login_share_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> wifi_web_auth_applet_mode{
linkage, AppletMode::HLE, "wifi_web_auth_applet_mode", Category::LibraryApplet};
Setting<AppletMode> my_page_applet_mode{linkage, AppletMode::LLE, "my_page_applet_mode",
Category::LibraryApplet};
// Audio // Audio
SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine", SwitchableSetting<AudioEngine> sink_id{linkage, AudioEngine::Auto, "output_engine",
Category::Audio, Specialization::RuntimeList}; Category::Audio, Specialization::RuntimeList};

View File

@ -44,6 +44,7 @@ enum class Category : u32 {
Services, Services,
Paths, Paths,
Linux, Linux,
LibraryApplet,
MaxEnum, MaxEnum,
}; };

View File

@ -151,6 +151,8 @@ ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked); ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE);
template <typename Type> template <typename Type>
inline std::string CanonicalizeEnum(Type id) { inline std::string CanonicalizeEnum(Type id) {
const auto group = EnumMetadata<Type>::Canonicalizations(); const auto group = EnumMetadata<Type>::Canonicalizations();

View File

@ -14,7 +14,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/polyfill_ranges.h" #include "common/polyfill_ranges.h"
namespace VideoCommon { namespace Common {
struct SlotId { struct SlotId {
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max(); static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
@ -217,11 +217,11 @@ private:
std::vector<u32> free_list; std::vector<u32> free_list;
}; };
} // namespace VideoCommon } // namespace Common
template <> template <>
struct std::hash<VideoCommon::SlotId> { struct std::hash<Common::SlotId> {
size_t operator()(const VideoCommon::SlotId& id) const noexcept { size_t operator()(const Common::SlotId& id) const noexcept {
return std::hash<u32>{}(id.index); return std::hash<u32>{}(id.index);
} }
}; };

View File

@ -186,68 +186,68 @@ static_assert(std::is_trivially_destructible_v<PhysicalAddress>);
static_assert(std::is_trivially_destructible_v<VirtualAddress>); static_assert(std::is_trivially_destructible_v<VirtualAddress>);
static_assert(std::is_trivially_destructible_v<ProcessAddress>); static_assert(std::is_trivially_destructible_v<ProcessAddress>);
static_assert(Null<uint64_t> == 0); static_assert(Null<uint64_t> == 0U);
static_assert(Null<PhysicalAddress> == Null<uint64_t>); static_assert(Null<PhysicalAddress> == Null<uint64_t>);
static_assert(Null<VirtualAddress> == Null<uint64_t>); static_assert(Null<VirtualAddress> == Null<uint64_t>);
static_assert(Null<ProcessAddress> == Null<uint64_t>); static_assert(Null<ProcessAddress> == Null<uint64_t>);
// Constructor/assignment validations. // Constructor/assignment validations.
static_assert([] { static_assert([] {
const PhysicalAddress a(5); const PhysicalAddress a(5U);
PhysicalAddress b(a); PhysicalAddress b(a);
return b; return b;
}() == PhysicalAddress(5)); }() == PhysicalAddress(5U));
static_assert([] { static_assert([] {
const PhysicalAddress a(5); const PhysicalAddress a(5U);
PhysicalAddress b(10); PhysicalAddress b(10U);
b = a; b = a;
return b; return b;
}() == PhysicalAddress(5)); }() == PhysicalAddress(5U));
// Arithmetic validations. // Arithmetic validations.
static_assert(PhysicalAddress(10) + 5 == PhysicalAddress(15)); static_assert(PhysicalAddress(10U) + 5U == PhysicalAddress(15U));
static_assert(PhysicalAddress(10) - 5 == PhysicalAddress(5)); static_assert(PhysicalAddress(10U) - 5U == PhysicalAddress(5U));
static_assert([] { static_assert([] {
PhysicalAddress v(10); PhysicalAddress v(10U);
v += 5; v += 5U;
return v; return v;
}() == PhysicalAddress(15)); }() == PhysicalAddress(15U));
static_assert([] { static_assert([] {
PhysicalAddress v(10); PhysicalAddress v(10U);
v -= 5; v -= 5U;
return v; return v;
}() == PhysicalAddress(5)); }() == PhysicalAddress(5U));
static_assert(PhysicalAddress(10)++ == PhysicalAddress(10)); static_assert(PhysicalAddress(10U)++ == PhysicalAddress(10U));
static_assert(++PhysicalAddress(10) == PhysicalAddress(11)); static_assert(++PhysicalAddress(10U) == PhysicalAddress(11U));
static_assert(PhysicalAddress(10)-- == PhysicalAddress(10)); static_assert(PhysicalAddress(10U)-- == PhysicalAddress(10U));
static_assert(--PhysicalAddress(10) == PhysicalAddress(9)); static_assert(--PhysicalAddress(10U) == PhysicalAddress(9U));
// Logical validations. // Logical validations.
static_assert((PhysicalAddress(0b11111111) >> 1) == 0b01111111); static_assert((PhysicalAddress(0b11111111U) >> 1) == 0b01111111U);
static_assert((PhysicalAddress(0b10101010) >> 1) == 0b01010101); static_assert((PhysicalAddress(0b10101010U) >> 1) == 0b01010101U);
static_assert((PhysicalAddress(0b11111111) << 1) == 0b111111110); static_assert((PhysicalAddress(0b11111111U) << 1) == 0b111111110U);
static_assert((PhysicalAddress(0b01010101) << 1) == 0b10101010); static_assert((PhysicalAddress(0b01010101U) << 1) == 0b10101010U);
static_assert((PhysicalAddress(0b11111111) & 0b01010101) == 0b01010101); static_assert((PhysicalAddress(0b11111111U) & 0b01010101U) == 0b01010101U);
static_assert((PhysicalAddress(0b11111111) & 0b10101010) == 0b10101010); static_assert((PhysicalAddress(0b11111111U) & 0b10101010U) == 0b10101010U);
static_assert((PhysicalAddress(0b01010101) & 0b10101010) == 0b00000000); static_assert((PhysicalAddress(0b01010101U) & 0b10101010U) == 0b00000000U);
static_assert((PhysicalAddress(0b00000000) | 0b01010101) == 0b01010101); static_assert((PhysicalAddress(0b00000000U) | 0b01010101U) == 0b01010101U);
static_assert((PhysicalAddress(0b11111111) | 0b01010101) == 0b11111111); static_assert((PhysicalAddress(0b11111111U) | 0b01010101U) == 0b11111111U);
static_assert((PhysicalAddress(0b10101010) | 0b01010101) == 0b11111111); static_assert((PhysicalAddress(0b10101010U) | 0b01010101U) == 0b11111111U);
// Comparisons. // Comparisons.
static_assert(PhysicalAddress(0) == PhysicalAddress(0)); static_assert(PhysicalAddress(0U) == PhysicalAddress(0U));
static_assert(PhysicalAddress(0) != PhysicalAddress(1)); static_assert(PhysicalAddress(0U) != PhysicalAddress(1U));
static_assert(PhysicalAddress(0) < PhysicalAddress(1)); static_assert(PhysicalAddress(0U) < PhysicalAddress(1U));
static_assert(PhysicalAddress(0) <= PhysicalAddress(1)); static_assert(PhysicalAddress(0U) <= PhysicalAddress(1U));
static_assert(PhysicalAddress(1) > PhysicalAddress(0)); static_assert(PhysicalAddress(1U) > PhysicalAddress(0U));
static_assert(PhysicalAddress(1) >= PhysicalAddress(0)); static_assert(PhysicalAddress(1U) >= PhysicalAddress(0U));
static_assert(!(PhysicalAddress(0) == PhysicalAddress(1))); static_assert(!(PhysicalAddress(0U) == PhysicalAddress(1U)));
static_assert(!(PhysicalAddress(0) != PhysicalAddress(0))); static_assert(!(PhysicalAddress(0U) != PhysicalAddress(0U)));
static_assert(!(PhysicalAddress(1) < PhysicalAddress(0))); static_assert(!(PhysicalAddress(1U) < PhysicalAddress(0U)));
static_assert(!(PhysicalAddress(1) <= PhysicalAddress(0))); static_assert(!(PhysicalAddress(1U) <= PhysicalAddress(0U)));
static_assert(!(PhysicalAddress(0) > PhysicalAddress(1))); static_assert(!(PhysicalAddress(0U) > PhysicalAddress(1U)));
static_assert(!(PhysicalAddress(0) >= PhysicalAddress(1))); static_assert(!(PhysicalAddress(0U) >= PhysicalAddress(1U)));
} // namespace Common } // namespace Common

View File

@ -439,6 +439,8 @@ add_library(core STATIC
hle/service/am/audio_controller.h hle/service/am/audio_controller.h
hle/service/am/common_state_getter.cpp hle/service/am/common_state_getter.cpp
hle/service/am/common_state_getter.h hle/service/am/common_state_getter.h
hle/service/am/cradle_firmware_updater.cpp
hle/service/am/cradle_firmware_updater.h
hle/service/am/debug_functions.cpp hle/service/am/debug_functions.cpp
hle/service/am/debug_functions.h hle/service/am/debug_functions.h
hle/service/am/display_controller.cpp hle/service/am/display_controller.cpp
@ -512,10 +514,35 @@ add_library(core STATIC
hle/service/audio/hwopus.h hle/service/audio/hwopus.h
hle/service/bcat/backend/backend.cpp hle/service/bcat/backend/backend.cpp
hle/service/bcat/backend/backend.h hle/service/bcat/backend/backend.h
hle/service/bcat/news/newly_arrived_event_holder.cpp
hle/service/bcat/news/newly_arrived_event_holder.h
hle/service/bcat/news/news_data_service.cpp
hle/service/bcat/news/news_data_service.h
hle/service/bcat/news/news_database_service.cpp
hle/service/bcat/news/news_database_service.h
hle/service/bcat/news/news_service.cpp
hle/service/bcat/news/news_service.h
hle/service/bcat/news/overwrite_event_holder.cpp
hle/service/bcat/news/overwrite_event_holder.h
hle/service/bcat/news/service_creator.cpp
hle/service/bcat/news/service_creator.h
hle/service/bcat/bcat.cpp hle/service/bcat/bcat.cpp
hle/service/bcat/bcat.h hle/service/bcat/bcat.h
hle/service/bcat/bcat_module.cpp hle/service/bcat/bcat_result.h
hle/service/bcat/bcat_module.h hle/service/bcat/bcat_service.cpp
hle/service/bcat/bcat_service.h
hle/service/bcat/bcat_types.h
hle/service/bcat/bcat_util.h
hle/service/bcat/delivery_cache_directory_service.cpp
hle/service/bcat/delivery_cache_directory_service.h
hle/service/bcat/delivery_cache_file_service.cpp
hle/service/bcat/delivery_cache_file_service.h
hle/service/bcat/delivery_cache_progress_service.cpp
hle/service/bcat/delivery_cache_progress_service.h
hle/service/bcat/delivery_cache_storage_service.cpp
hle/service/bcat/delivery_cache_storage_service.h
hle/service/bcat/service_creator.cpp
hle/service/bcat/service_creator.h
hle/service/bpc/bpc.cpp hle/service/bpc/bpc.cpp
hle/service/bpc/bpc.h hle/service/bpc/bpc.h
hle/service/btdrv/btdrv.cpp hle/service/btdrv/btdrv.cpp
@ -548,8 +575,6 @@ add_library(core STATIC
hle/service/es/es.h hle/service/es/es.h
hle/service/eupld/eupld.cpp hle/service/eupld/eupld.cpp
hle/service/eupld/eupld.h hle/service/eupld/eupld.h
hle/service/event.cpp
hle/service/event.h
hle/service/fatal/fatal.cpp hle/service/fatal/fatal.cpp
hle/service/fatal/fatal.h hle/service/fatal/fatal.h
hle/service/fatal/fatal_p.cpp hle/service/fatal/fatal_p.cpp
@ -676,8 +701,6 @@ add_library(core STATIC
hle/service/mm/mm_u.h hle/service/mm/mm_u.h
hle/service/mnpp/mnpp_app.cpp hle/service/mnpp/mnpp_app.cpp
hle/service/mnpp/mnpp_app.h hle/service/mnpp/mnpp_app.h
hle/service/mutex.cpp
hle/service/mutex.h
hle/service/ncm/ncm.cpp hle/service/ncm/ncm.cpp
hle/service/ncm/ncm.h hle/service/ncm/ncm.h
hle/service/nfc/common/amiibo_crypto.cpp hle/service/nfc/common/amiibo_crypto.cpp
@ -775,6 +798,9 @@ add_library(core STATIC
hle/service/nvnflinger/graphic_buffer_producer.h hle/service/nvnflinger/graphic_buffer_producer.h
hle/service/nvnflinger/hos_binder_driver_server.cpp hle/service/nvnflinger/hos_binder_driver_server.cpp
hle/service/nvnflinger/hos_binder_driver_server.h hle/service/nvnflinger/hos_binder_driver_server.h
hle/service/nvnflinger/hardware_composer.cpp
hle/service/nvnflinger/hardware_composer.h
hle/service/nvnflinger/hwc_layer.h
hle/service/nvnflinger/nvnflinger.cpp hle/service/nvnflinger/nvnflinger.cpp
hle/service/nvnflinger/nvnflinger.h hle/service/nvnflinger/nvnflinger.h
hle/service/nvnflinger/parcel.h hle/service/nvnflinger/parcel.h
@ -787,6 +813,15 @@ add_library(core STATIC
hle/service/nvnflinger/window.h hle/service/nvnflinger/window.h
hle/service/olsc/olsc.cpp hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h hle/service/olsc/olsc.h
hle/service/os/event.cpp
hle/service/os/event.h
hle/service/os/multi_wait_holder.cpp
hle/service/os/multi_wait_holder.h
hle/service/os/multi_wait_utils.h
hle/service/os/multi_wait.cpp
hle/service/os/multi_wait.h
hle/service/os/mutex.cpp
hle/service/os/mutex.h
hle/service/pcie/pcie.cpp hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h hle/service/pcie/pcie.h
hle/service/pctl/pctl.cpp hle/service/pctl/pctl.cpp

View File

@ -383,7 +383,7 @@ std::string GDBStubA32::RegRead(const Kernel::KThread* thread, size_t id) const
} else if (id == CPSR_REGISTER) { } else if (id == CPSR_REGISTER) {
return ValueToHex(context.pstate); return ValueToHex(context.pstate);
} else if (id >= D0_REGISTER && id < Q0_REGISTER) { } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
return ValueToHex(fprs[id - D0_REGISTER][0]); return ValueToHex(fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2]);
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
return ValueToHex(fprs[id - Q0_REGISTER]); return ValueToHex(fprs[id - Q0_REGISTER]);
} else if (id == FPSCR_REGISTER) { } else if (id == FPSCR_REGISTER) {
@ -406,7 +406,7 @@ void GDBStubA32::RegWrite(Kernel::KThread* thread, size_t id, std::string_view v
} else if (id == CPSR_REGISTER) { } else if (id == CPSR_REGISTER) {
context.pstate = HexToValue<u32>(value); context.pstate = HexToValue<u32>(value);
} else if (id >= D0_REGISTER && id < Q0_REGISTER) { } else if (id >= D0_REGISTER && id < Q0_REGISTER) {
fprs[id - D0_REGISTER] = {HexToValue<u64>(value), 0}; fprs[(id - D0_REGISTER) / 2][(id - D0_REGISTER) % 2] = HexToValue<u64>(value);
} else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) { } else if (id >= Q0_REGISTER && id < FPSCR_REGISTER) {
fprs[id - Q0_REGISTER] = HexToValue<u128>(value); fprs[id - Q0_REGISTER] = HexToValue<u128>(value);
} else if (id == FPSCR_REGISTER) { } else if (id == FPSCR_REGISTER) {

View File

@ -532,6 +532,7 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
cache_bytes = 0; cache_bytes = 0;
} }
}; };
size_t old_vpage = (base_vaddress >> Memory::YUZU_PAGEBITS) - 1;
for (; page != page_end; ++page) { for (; page != page_end; ++page) {
CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page); CounterAtomicType& count = cached_pages->at(page >> subentries_shift).Count(page);
auto [asid_2, vpage] = ExtractCPUBacking(page); auto [asid_2, vpage] = ExtractCPUBacking(page);
@ -547,6 +548,12 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
memory_device_inter = registered_processes[asid_2.id]; memory_device_inter = registered_processes[asid_2.id];
} }
if (vpage != old_vpage + 1) [[unlikely]] {
release_pending();
}
old_vpage = vpage;
// Adds or subtracts 1, as count is a unsigned 8-bit value // Adds or subtracts 1, as count is a unsigned 8-bit value
count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release); count.fetch_add(static_cast<CounterType>(delta), std::memory_order_release);

View File

@ -172,6 +172,10 @@ u32 NCA::GetSDKVersion() const {
return reader->GetSdkAddonVersion(); return reader->GetSdkAddonVersion();
} }
u8 NCA::GetKeyGeneration() const {
return reader->GetKeyGeneration();
}
bool NCA::IsUpdate() const { bool NCA::IsUpdate() const {
return is_update; return is_update;
} }

View File

@ -77,6 +77,7 @@ public:
u64 GetTitleId() const; u64 GetTitleId() const;
RightsId GetRightsId() const; RightsId GetRightsId() const;
u32 GetSDKVersion() const; u32 GetSDKVersion() const;
u8 GetKeyGeneration() const;
bool IsUpdate() const; bool IsUpdate() const;
VirtualFile GetRomFS() const; VirtualFile GetRomFS() const;

View File

@ -91,6 +91,7 @@ constexpr Result ResultWriteNotPermitted{ErrorModule::FS, 6203};
constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 6325}; constexpr Result ResultUnsupportedSetSizeForIndirectStorage{ErrorModule::FS, 6325};
constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387}; constexpr Result ResultUnsupportedWriteForCompressedStorage{ErrorModule::FS, 6387};
constexpr Result ResultUnsupportedOperateRangeForCompressedStorage{ErrorModule::FS, 6388}; constexpr Result ResultUnsupportedOperateRangeForCompressedStorage{ErrorModule::FS, 6388};
constexpr Result ResultPermissionDenied{ErrorModule::FS, 6400};
constexpr Result ResultBufferAllocationFailed{ErrorModule::FS, 6705}; constexpr Result ResultBufferAllocationFailed{ErrorModule::FS, 6705};
} // namespace FileSys } // namespace FileSys

View File

@ -4,8 +4,9 @@
#include <random> #include <random>
#include "common/scope_exit.h" #include "common/scope_exit.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core.h" #include "core/core.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scoped_resource_reservation.h" #include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
@ -1258,6 +1259,10 @@ void KProcess::InitializeInterfaces() {
#ifdef HAS_NCE #ifdef HAS_NCE
if (this->IsApplication() && Settings::IsNceEnabled()) { if (this->IsApplication() && Settings::IsNceEnabled()) {
// Register the scoped JIT handler before creating any NCE instances
// so that its signal handler will appear first in the signal chain.
Core::ScopedJitExecution::RegisterHandler();
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
} }

View File

@ -96,9 +96,10 @@ public:
{133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+ {133, nullptr, "GetNintendoAccountVerificationUrlCache"}, // 9.0.0+
{134, nullptr, "RefreshNintendoAccountVerificationUrlCache"}, // 9.0.0+ {134, nullptr, "RefreshNintendoAccountVerificationUrlCache"}, // 9.0.0+
{135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+ {135, nullptr, "RefreshNintendoAccountVerificationUrlCacheAsyncIfSecondsElapsed"}, // 9.0.0+
{140, nullptr, "GetNetworkServiceLicenseCache"}, // 5.0.0+ {140, &IManagerForSystemService::GetNetworkServiceLicenseCache, "GetNetworkServiceLicenseCache"}, // 5.0.0+
{141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+ {141, nullptr, "RefreshNetworkServiceLicenseCacheAsync"}, // 5.0.0+
{142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+ {142, nullptr, "RefreshNetworkServiceLicenseCacheAsyncIfSecondsElapsed"}, // 5.0.0+
{143, &IManagerForSystemService::Unknown143, "Unknown143"},
{150, nullptr, "CreateAuthorizationRequest"}, {150, nullptr, "CreateAuthorizationRequest"},
{160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"}, {160, nullptr, "RequiresUpdateNetworkServiceAccountIdTokenCache"},
{161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"}, {161, nullptr, "RequireReauthenticationOfNetworkServiceAccount"},
@ -114,6 +115,24 @@ private:
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void GetNetworkServiceLicenseCache(HLERequestContext& ctx) {
LOG_ERROR(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.Push<u64>(0);
rb.Push<u64>(0);
}
void Unknown143(HLERequestContext& ctx) {
LOG_ERROR(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.Push<u64>(0);
rb.Push<u64>(0);
}
}; };
// 3.0.0+ // 3.0.0+

View File

@ -329,7 +329,7 @@ bool ProfileManager::GetProfileBaseAndData(const ProfileInfo& user, ProfileBase&
/// Returns if the system is allowing user registrations or not /// Returns if the system is allowing user registrations or not
bool ProfileManager::CanSystemRegisterUser() const { bool ProfileManager::CanSystemRegisterUser() const {
return false; // TODO(ogniK): Games shouldn't have return true; // TODO(ogniK): Games shouldn't have
// access to user registration, when we // access to user registration, when we
// emulate qlaunch. Update this to dynamically change. // emulate qlaunch. Update this to dynamically change.
} }

View File

@ -130,9 +130,9 @@ enum class AppletProgramId : u64 {
enum class LibraryAppletMode : u32 { enum class LibraryAppletMode : u32 {
AllForeground = 0, AllForeground = 0,
Background = 1, PartialForeground = 1,
NoUI = 2, NoUi = 2,
BackgroundIndirectDisplay = 3, PartialForegroundIndirectDisplay = 3,
AllForegroundInitiallyHidden = 4, AllForegroundInitiallyHidden = 4,
}; };

View File

@ -9,8 +9,8 @@
#include "common/math_util.h" #include "common/math_util.h"
#include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/caps/caps_types.h" #include "core/hle/service/caps/caps_types.h"
#include "core/hle/service/event.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hle/service/am/am_types.h" #include "core/hle/service/am/am_types.h"

View File

@ -29,6 +29,7 @@ private:
void OpenSystemAppletProxy(HLERequestContext& ctx); void OpenSystemAppletProxy(HLERequestContext& ctx);
void OpenLibraryAppletProxy(HLERequestContext& ctx); void OpenLibraryAppletProxy(HLERequestContext& ctx);
void OpenLibraryAppletProxyOld(HLERequestContext& ctx); void OpenLibraryAppletProxyOld(HLERequestContext& ctx);
void OpenOverlayAppletProxy(HLERequestContext& ctx);
std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx); std::shared_ptr<Applet> GetAppletFromContext(HLERequestContext& ctx);

View File

@ -7,8 +7,8 @@
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include "core/hle/service/event.h"
#include "core/hle/service/kernel_helpers.h" #include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
union Result; union Result;

View File

@ -206,6 +206,41 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan
channel.Push(std::make_shared<IStorage>(system, std::move(work_buffer))); channel.Push(std::make_shared<IStorage>(system, std::move(work_buffer)));
} }
void PushInShowMyPageData(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = 0,
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
std::vector<u8> argument_data(sizeof(arguments));
std::vector<u8> settings_data{0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE,
0x9E, 0xF8, 0xAF, 0xB1, 0xE8, 0x95, 0x90, 0x33, 0x6C,
0x0B, 0x22, 0x70, 0x07, 0xF4, 0xBB, 0x00};
settings_data.resize(0x10a8);
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(settings_data)));
}
void PushInShowQlaunch(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = 0,
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
std::vector<u8> argument_data(sizeof(arguments));
std::memcpy(argument_data.data(), &arguments, sizeof(arguments));
channel.Push(std::make_shared<IStorage>(system, std::move(argument_data)));
}
} // namespace } // namespace
AppletManager::AppletManager(Core::System& system) : m_system(system) {} AppletManager::AppletManager(Core::System& system) : m_system(system) {}
@ -298,6 +333,12 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters(
case AppletId::Controller: case AppletId::Controller:
PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet)); PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet));
break; break;
case AppletId::MyPage:
PushInShowMyPageData(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
case AppletId::QLaunch:
PushInShowQlaunch(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
default: default:
break; break;
} }

View File

@ -6,11 +6,49 @@
namespace Service::AM { namespace Service::AM {
IApplicationAccessor::IApplicationAccessor(Core::System& system_, u64 application_id)
: ServiceFramework{system_, "IApplicationAccessor"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAppletStateChangedEvent"},
{1, nullptr, "IsCompleted"},
{10, nullptr, "Start"},
{20, nullptr, "RequestExit"},
{25, nullptr, "Terminate"},
{30, nullptr, "GetResult"},
{101, nullptr, "RequestForApplicationToGetForeground"},
{110, nullptr, "TerminateAllLibraryApplets"},
{111, nullptr, "AreAnyLibraryAppletsLeft"},
{112, nullptr, "GetCurrentLibraryApplet"},
{120, nullptr, "GetApplicationId"},
{121, nullptr, "PushLaunchParameter"},
{122, nullptr, "GetApplicationControlProperty"},
{123, nullptr, "GetApplicationLaunchProperty"},
{124, nullptr, "GetApplicationLaunchRequestInfo"},
{130, nullptr, "SetUsers"},
{131, nullptr, "CheckRightsEnvironmentAvailable"},
{132, nullptr, "GetNsRightsEnvironmentHandle"},
{140, nullptr, "GetDesirableUids"},
{150, nullptr, "ReportApplicationExitTimeout"},
{160, nullptr, "SetApplicationAttribute"},
{170, nullptr, "HasSaveDataAccessPermission"},
{180, nullptr, "PushToFriendInvitationStorageChannel"},
{190, nullptr, "PushToNotificationStorageChannel"},
{200, nullptr, "RequestApplicationSoftReset"},
{201, nullptr, "RestartApplicationTimer"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationAccessor::~IApplicationAccessor() = default;
IApplicationCreator::IApplicationCreator(Core::System& system_) IApplicationCreator::IApplicationCreator(Core::System& system_)
: ServiceFramework{system_, "IApplicationCreator"} { : ServiceFramework{system_, "IApplicationCreator"} {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, nullptr, "CreateApplication"}, {0, &IApplicationCreator::CreateApplication, "CreateApplication"},
{1, nullptr, "PopLaunchRequestedApplication"}, {1, nullptr, "PopLaunchRequestedApplication"},
{10, nullptr, "CreateSystemApplication"}, {10, nullptr, "CreateSystemApplication"},
{100, nullptr, "PopFloatingApplicationForDevelopment"}, {100, nullptr, "PopFloatingApplicationForDevelopment"},
@ -22,4 +60,15 @@ IApplicationCreator::IApplicationCreator(Core::System& system_)
IApplicationCreator::~IApplicationCreator() = default; IApplicationCreator::~IApplicationCreator() = default;
void IApplicationCreator::CreateApplication(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto application_id = rp.Pop<u64>();
LOG_ERROR(Service_NS, "called, application_id={:x}", application_id);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IApplicationAccessor>(system, application_id);
}
} // namespace Service::AM } // namespace Service::AM

View File

@ -7,10 +7,21 @@
namespace Service::AM { namespace Service::AM {
class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> {
public:
explicit IApplicationAccessor(Core::System& system_, u64 application_id);
~IApplicationAccessor() override;
private:
};
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> { class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
public: public:
explicit IApplicationCreator(Core::System& system_); explicit IApplicationCreator(Core::System& system_);
~IApplicationCreator() override; ~IApplicationCreator() override;
private:
void CreateApplication(HLERequestContext& ctx);
}; };
} // namespace Service::AM } // namespace Service::AM

View File

@ -37,7 +37,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
{20, nullptr, "PushToGeneralChannel"}, {20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"}, {30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"}, {31, &ICommonStateGetter::GetReaderLockAccessorEx, "GetReaderLockAccessorEx"},
{32, nullptr, "GetWriterLockAccessorEx"}, {32, &ICommonStateGetter::GetWriterLockAccessorEx, "GetWriterLockAccessorEx"},
{40, nullptr, "GetCradleFwVersion"}, {40, nullptr, "GetCradleFwVersion"},
{50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"}, {50, &ICommonStateGetter::IsVrModeEnabled, "IsVrModeEnabled"},
{51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"}, {51, &ICommonStateGetter::SetVrModeEnabled, "SetVrModeEnabled"},
@ -61,7 +61,7 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
{100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"}, {100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
{110, nullptr, "OpenMyGpuErrorHandler"}, {110, nullptr, "OpenMyGpuErrorHandler"},
{120, &ICommonStateGetter::GetAppletLaunchedHistory, "GetAppletLaunchedHistory"}, {120, &ICommonStateGetter::GetAppletLaunchedHistory, "GetAppletLaunchedHistory"},
{200, nullptr, "GetOperationModeSystemInfo"}, {200, &ICommonStateGetter::GetOperationModeSystemInfo, "GetOperationModeSystemInfo"},
{300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"}, {300, &ICommonStateGetter::GetSettingsPlatformRegion, "GetSettingsPlatformRegion"},
{400, nullptr, "ActivateMigrationService"}, {400, nullptr, "ActivateMigrationService"},
{401, nullptr, "DeactivateMigrationService"}, {401, nullptr, "DeactivateMigrationService"},
@ -160,6 +160,15 @@ void ICommonStateGetter::GetReaderLockAccessorEx(HLERequestContext& ctx) {
rb.PushIpcInterface<ILockAccessor>(system); rb.PushIpcInterface<ILockAccessor>(system);
} }
void ICommonStateGetter::GetWriterLockAccessorEx(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ILockAccessor>(system);
}
void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) { void ICommonStateGetter::GetAcquiredSleepLockEvent(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "called"); LOG_WARNING(Service_AM, "called");
@ -271,6 +280,14 @@ void ICommonStateGetter::PerformSystemButtonPressingIfInFocus(HLERequestContext&
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void ICommonStateGetter::GetOperationModeSystemInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
void ICommonStateGetter::GetAppletLaunchedHistory(HLERequestContext& ctx) { void ICommonStateGetter::GetAppletLaunchedHistory(HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called"); LOG_WARNING(Service_AM, "(STUBBED) called");

View File

@ -54,6 +54,7 @@ private:
void RequestToAcquireSleepLock(HLERequestContext& ctx); void RequestToAcquireSleepLock(HLERequestContext& ctx);
void GetAcquiredSleepLockEvent(HLERequestContext& ctx); void GetAcquiredSleepLockEvent(HLERequestContext& ctx);
void GetReaderLockAccessorEx(HLERequestContext& ctx); void GetReaderLockAccessorEx(HLERequestContext& ctx);
void GetWriterLockAccessorEx(HLERequestContext& ctx);
void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx); void GetDefaultDisplayResolutionChangeEvent(HLERequestContext& ctx);
void GetOperationMode(HLERequestContext& ctx); void GetOperationMode(HLERequestContext& ctx);
void GetPerformanceMode(HLERequestContext& ctx); void GetPerformanceMode(HLERequestContext& ctx);
@ -68,6 +69,7 @@ private:
void GetBuiltInDisplayType(HLERequestContext& ctx); void GetBuiltInDisplayType(HLERequestContext& ctx);
void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx); void PerformSystemButtonPressingIfInFocus(HLERequestContext& ctx);
void GetAppletLaunchedHistory(HLERequestContext& ctx); void GetAppletLaunchedHistory(HLERequestContext& ctx);
void GetOperationModeSystemInfo(HLERequestContext& ctx);
void GetSettingsPlatformRegion(HLERequestContext& ctx); void GetSettingsPlatformRegion(HLERequestContext& ctx);
void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx); void SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled(HLERequestContext& ctx);

Some files were not shown because too many files have changed in this diff Show More