From b52600ffc4c73090f186da6471382593fef949c6 Mon Sep 17 00:00:00 2001 From: programminghoch10 <16062290+programminghoch10@users.noreply.github.com> Date: Sat, 23 Aug 2025 23:51:59 +0200 Subject: [PATCH 1/5] implement SettingsActivity for RotationControl --- RotationControl/build.gradle.kts | 8 +- RotationControl/src/main/AndroidManifest.xml | 19 ++- .../RotationControl/ROTATION_MODE.kt | 139 ++++++++++++++++++ .../RotationControl/RadioPreference.kt | 23 +++ .../RotationControl/SettingsActivity.kt | 55 +++++++ .../RotationControl/XposedHook.java | 46 ------ .../RotationControl/XposedHook.kt | 53 +++++++ RotationControl/src/main/res/layout/radio.xml | 9 ++ .../src/main/res/layout/settings_activity.xml | 11 ++ .../src/main/res/values-v21/themes.xml | 5 + .../src/main/res/values/strings.xml | 6 + .../src/main/res/values/themes.xml | 9 ++ .../src/main/res/xml/root_preferences.xml | 7 + gradle/libs.versions.toml | 3 + 14 files changed, 343 insertions(+), 50 deletions(-) create mode 100644 RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt create mode 100644 RotationControl/src/main/java/com/programminghoch10/RotationControl/RadioPreference.kt create mode 100644 RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt delete mode 100644 RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.java create mode 100644 RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt create mode 100644 RotationControl/src/main/res/layout/radio.xml create mode 100644 RotationControl/src/main/res/layout/settings_activity.xml create mode 100644 RotationControl/src/main/res/values-v21/themes.xml create mode 100644 RotationControl/src/main/res/values/strings.xml create mode 100644 RotationControl/src/main/res/values/themes.xml create mode 100644 RotationControl/src/main/res/xml/root_preferences.xml diff --git a/RotationControl/build.gradle.kts b/RotationControl/build.gradle.kts index 581ca0d..72a97fb 100644 --- a/RotationControl/build.gradle.kts +++ b/RotationControl/build.gradle.kts @@ -1,5 +1,6 @@ plugins { alias(libs.plugins.buildlogic.android.application) + alias(libs.plugins.kotlin.android) } android { @@ -9,6 +10,11 @@ android { defaultConfig { applicationId = packageName minSdk = 24 - targetSdk = 33 + targetSdk = 36 } } + +dependencies { + implementation(libs.androidx.fragment.ktx) + implementation(libs.androidx.preference.ktx) +} diff --git a/RotationControl/src/main/AndroidManifest.xml b/RotationControl/src/main/AndroidManifest.xml index f84483a..b8980a2 100644 --- a/RotationControl/src/main/AndroidManifest.xml +++ b/RotationControl/src/main/AndroidManifest.xml @@ -2,18 +2,31 @@ - + + + + + + + + = mutableListOf() + + @SuppressLint("WorldReadableFiles") + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.root_preferences, rootKey) + preferenceManager.sharedPreferencesName = SHARED_PREFERENCES_NAME + preferenceManager.sharedPreferencesMode = MODE_WORLD_READABLE + val preferenceCategory = findPreference("category_rotation_mode")!! + val context = requireContext() + + for (rotationMode in ROTATION_MODE.entries) { + val preference = RadioPreference(context) + preference.key = rotationMode.key + preference.title = rotationMode.title + preference.summary = rotationMode.summary + preference.setDefaultValue(rotationMode == ROTATION_MODE_DEFAULT) + radioPreferences.add(preference) + preference.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { preference, newValue -> + radioPreferences.forEach { it.onRadioPreferenceSelected(preference as RadioPreference) } + true + } + preferenceCategory.addPreference(preference) + } + } + } +} diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.java b/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.java deleted file mode 100644 index 05cdd98..0000000 --- a/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.programminghoch10.RotationControl; - -import android.app.Activity; -import android.content.Context; -import android.content.ContextWrapper; -import android.content.pm.ActivityInfo; -import android.view.Window; - -import de.robv.android.xposed.IXposedHookLoadPackage; -import de.robv.android.xposed.XC_MethodHook; -import de.robv.android.xposed.XposedHelpers; -import de.robv.android.xposed.callbacks.XC_LoadPackage; - -public class XposedHook implements IXposedHookLoadPackage { - @Override - public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { - XposedHelpers.findAndHookMethod( - Activity.class, "setRequestedOrientation", int.class, new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) { - param.args[0] = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR; - } - } - ); - XposedHelpers.findAndHookMethod( - "com.android.internal.policy.PhoneWindow", - lpparam.classLoader, - "generateLayout", - "com.android.internal.policy.DecorView", - new XC_MethodHook() { - @Override - protected void beforeHookedMethod(MethodHookParam param) { - Context context = ((Window) param.thisObject).getContext(); - - while (context instanceof ContextWrapper) { - if (context instanceof Activity activity) { - activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); - return; - } - context = ((ContextWrapper) context).getBaseContext(); - } - } - } - ); - } -} diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt new file mode 100644 index 0000000..b7985c5 --- /dev/null +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt @@ -0,0 +1,53 @@ +package com.programminghoch10.RotationControl + +import android.app.Activity +import android.content.ContextWrapper +import android.content.SharedPreferences +import android.content.pm.ActivityInfo +import android.view.Window +import de.robv.android.xposed.IXposedHookLoadPackage +import de.robv.android.xposed.XC_MethodHook +import de.robv.android.xposed.XSharedPreferences +import de.robv.android.xposed.XposedHelpers +import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam + +class XposedHook : IXposedHookLoadPackage { + override fun handleLoadPackage(lpparam: LoadPackageParam) { + if (lpparam.packageName == BuildConfig.APPLICATION_ID) return + + XposedHelpers.findAndHookMethod( + Activity::class.java, + "setRequestedOrientation", + Int::class.java, + object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam) { + val sharedPreferences: SharedPreferences = XSharedPreferences(BuildConfig.APPLICATION_ID, SHARED_PREFERENCES_NAME) + val selectedRotationMode = ROTATION_MODE.entries.find { sharedPreferences.getBoolean(it.key, false) } ?: ROTATION_MODE_DEFAULT + if (selectedRotationMode == ROTATION_MODE.SCREEN_ORIENTATION_UNSET) return + param.args[0] = selectedRotationMode.value + } + }, + ) + + XposedHelpers.findAndHookMethod( + "com.android.internal.policy.PhoneWindow", + lpparam.classLoader, + "generateLayout", + "com.android.internal.policy.DecorView", + object : XC_MethodHook() { + override fun beforeHookedMethod(param: MethodHookParam) { + var context = (param.thisObject as Window).context + while (context is ContextWrapper) { + if (context is Activity) { + // we only need to call setRequestedOrientation + // the value doesn't matter, since the hook above replaces it + context.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + return + } + context = context.baseContext + } + } + }, + ) + } +} diff --git a/RotationControl/src/main/res/layout/radio.xml b/RotationControl/src/main/res/layout/radio.xml new file mode 100644 index 0000000..41de0b3 --- /dev/null +++ b/RotationControl/src/main/res/layout/radio.xml @@ -0,0 +1,9 @@ + + diff --git a/RotationControl/src/main/res/layout/settings_activity.xml b/RotationControl/src/main/res/layout/settings_activity.xml new file mode 100644 index 0000000..c716b52 --- /dev/null +++ b/RotationControl/src/main/res/layout/settings_activity.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/RotationControl/src/main/res/values-v21/themes.xml b/RotationControl/src/main/res/values-v21/themes.xml new file mode 100644 index 0000000..e15c2b9 --- /dev/null +++ b/RotationControl/src/main/res/values-v21/themes.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/RotationControl/src/main/res/xml/root_preferences.xml b/RotationControl/src/main/res/xml/root_preferences.xml new file mode 100644 index 0000000..3e89b30 --- /dev/null +++ b/RotationControl/src/main/res/xml/root_preferences.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c816fe7..6c57813 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,6 +5,7 @@ androidTools = "31.12.1" androidxAnnotation = "1.9.1" collection = "1.5.0" core = "1.17.0" +fragment = "1.8.9" githubApi = "1.329" hiddenapibypass = "6.1" jebrainsAnnotations = "26.0.2" @@ -20,7 +21,9 @@ android-tools-common = { module = "com.android.tools:common", version.ref = "and androidx-annotation = { module = "androidx.annotation:annotation", version.ref = "androidxAnnotation" } androidx-collection-ktx = { module = "androidx.collection:collection-ktx", version.ref = "collection" } androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "core" } +androidx-fragment-ktx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "fragment" } androidx-preference = { group = "androidx.preference", name = "preference", version.ref = "preference" } +androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "preference" } github-api = { module = "org.kohsuke:github-api", version.ref = "githubApi" } hiddenapibypass = { module = "org.lsposed.hiddenapibypass:hiddenapibypass", version.ref = "hiddenapibypass" } jebtrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jebrainsAnnotations" } From c2464da920c8849e46c39f6a6ea8ca5df1701871 Mon Sep 17 00:00:00 2001 From: programminghoch10 <16062290+programminghoch10@users.noreply.github.com> Date: Sun, 24 Aug 2025 00:10:49 +0200 Subject: [PATCH 2/5] extract ROTATION_MODE strings to resources --- .../RotationControl/ROTATION_MODE.kt | 100 +++++++----------- .../src/main/res/values/strings.xml | 34 ++++++ 2 files changed, 71 insertions(+), 63 deletions(-) diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt index ece4cc6..52ae166 100644 --- a/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt @@ -1,139 +1,113 @@ package com.programminghoch10.RotationControl +import android.app.Application import android.content.pm.ActivityInfo +val context = Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null) as Application + enum class ROTATION_MODE(val key: String, val value: Int, val title: String, val summary: String) { // yoinked from https://developer.android.com/reference/android/R.attr.html#screenOrientation SCREEN_ORIENTATION_UNSET( "UNSET", -2, - "UNSET", - "Do not override screen orientation. " + - "You might as well disable the module instead of using this option.", + context.getString(R.string.screen_orientation_unset_title), + context.getString(R.string.screen_orientation_unset_summary), ), SCREEN_ORIENTATION_UNSPECIFIED( "UNSPECIFIED", ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, - "UNSPECIFIED", - "No preference specified: " + - "let the system decide the best orientation. " + - "This will either be the orientation selected by the activity below, " + - "or the user's preferred orientation if this activity is the bottom of a task. " + - "If the user explicitly turned off sensor based orientation " + - "through settings sensor based device rotation will be ignored. " + - "If not by default sensor based orientation will be taken into account " + - "and the orientation will changed based on how the user rotates the device.", + context.getString(R.string.screen_orientation_unspecified_title), + context.getString(R.string.screen_orientation_unspecified_summary), ), SCREEN_ORIENTATION_LANDSCAPE( "LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, - "LANDSCAPE", - "Would like to have the screen in a landscape orientation: " + - "that is, with the display wider than it is tall, ignoring sensor data.", + context.getString(R.string.screen_orientation_landscape_title), + context.getString(R.string.screen_orientation_landscape_summary), ), SCREEN_ORIENTATION_PORTRAIT( "PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, - "PORTRAIT", - "Would like to have the screen in a portrait orientation: " + - "that is, with the display taller than it is wide, ignoring sensor data.", + context.getString(R.string.screen_orientation_portrait_title), + context.getString(R.string.screen_orientation_portrait_summary), ), SCREEN_ORIENTATION_USER( "USER", ActivityInfo.SCREEN_ORIENTATION_USER, - "USER", - "Use the user's current preferred orientation of the handset.", + context.getString(R.string.screen_orientation_user_title), + context.getString(R.string.screen_orientation_user_summary), ), SCREEN_ORIENTATION_BEHIND( "BEHIND", ActivityInfo.SCREEN_ORIENTATION_BEHIND, - "BEHIND", - "Keep the screen in the same orientation as whatever is behind this activity.", + context.getString(R.string.screen_orientation_behind_title), + context.getString(R.string.screen_orientation_behind_summary), ), SCREEN_ORIENTATION_SENSOR( "SENSOR", ActivityInfo.SCREEN_ORIENTATION_SENSOR, - "SENSOR", - "Orientation is determined by a physical orientation sensor: " + - "the display will rotate based on how the user moves the device. " + - "Ignores user's setting to turn off sensor-based rotation.", + context.getString(R.string.screen_orientation_sensor_title), + context.getString(R.string.screen_orientation_sensor_summary), ), SCREEN_ORIENTATION_NOSENSOR( "NOSENSOR", ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, - "NOSENSOR", - "Always ignore orientation determined by orientation sensor: " + - "the display will not rotate when the user moves the device.", + context.getString(R.string.screen_orientation_nosensor_title), + context.getString(R.string.screen_orientation_nosensor_summary), ), SCREEN_ORIENTATION_SENSOR_LANDSCAPE( "SENSOR_LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, - "SENSOR_LANDSCAPE", - "Would like to have the screen in landscape orientation, " + - "but can use the sensor to change which direction the screen is facing. ", + context.getString(R.string.screen_orientation_sensor_landscape_title), + context.getString(R.string.screen_orientation_sensor_landscape_summary), ), SCREEN_ORIENTATION_SENSOR_PORTRAIT( "SENSOR_PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, - "SENSOR_PORTRAIT", - "Would like to have the screen in portrait orientation, " + - "but can use the sensor to change which direction the screen is facing.", + context.getString(R.string.screen_orientation_sensor_portrait_title), + context.getString(R.string.screen_orientation_sensor_portrait_summary), ), SCREEN_ORIENTATION_REVERSE_LANDSCAPE( "REVERSE_LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, - "REVERSE_LANDSCAPE", - "Would like to have the screen in landscape orientation, " + - "turned in the opposite direction from normal landscape.", + context.getString(R.string.screen_orientation_reverse_landscape_title), + context.getString(R.string.screen_orientation_reverse_landscape_summary), ), SCREEN_ORIENTATION_REVERSE_PORTRAIT( "REVERSE_PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, - "REVERSE_PORTRAIT", - "Would like to have the screen in portrait orientation, " + - "turned in the opposite direction from normal portrait.", + context.getString(R.string.screen_orientation_reverse_portrait_title), + context.getString(R.string.screen_orientation_reverse_portrait_summary), ), SCREEN_ORIENTATION_FULL_SENSOR( "FULL_SENSOR", ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR, - "FULL_SENSOR", - "Orientation is determined by a physical orientation sensor: " + - "the display will rotate based on how the user moves the device. " + - "This allows any of the 4 possible rotations, " + - "regardless of what the device will normally do " + - "(for example some devices won't normally use 180 degree rotation).", + context.getString(R.string.screen_orientation_full_sensor_title), + context.getString(R.string.screen_orientation_full_sensor_summary), ), SCREEN_ORIENTATION_USER_LANDSCAPE( "USER_LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE, - "USER_LANDSCAPE", - "Would like to have the screen in landscape orientation, " + - "but if the user has enabled sensor-based rotation " + - "then we can use the sensor to change which direction the screen is facing.", + context.getString(R.string.screen_orientation_user_landscape), + context.getString(R.string.screen_orientation_user_landscape_summary), ), SCREEN_ORIENTATION_USER_PORTRAIT( "USER_PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT, - "USER_PORTRAIT", - "Would like to have the screen in portrait orientation, " + - "but if the user has enabled sensor-based rotation " + - "then we can use the sensor to change which direction the screen is facing.", + context.getString(R.string.screen_orientation_user_portrait_title), + context.getString(R.string.screen_orientation_user_portrait_summary), ), SCREEN_ORIENTATION_FULL_USER( "FULL_USER", ActivityInfo.SCREEN_ORIENTATION_FULL_USER, - "FULL_USER", - "Respect the user's sensor-based rotation preference, " + - "but if sensor-based rotation is enabled " + - "then allow the screen to rotate in all 4 possible directions " + - "regardless of what the device will normally do " + - "(for example some devices won't normally use 180 degree rotation).", + context.getString(R.string.screen_orientation_full_user_title), + context.getString(R.string.screen_orientation_full_user_summary), ), SCREEN_ORIENTATION_LOCKED( "LOCKED", ActivityInfo.SCREEN_ORIENTATION_LOCKED, - "LOCKED", - "Screen is locked to its current rotation, whatever that is.", + context.getString(R.string.screen_orientation_locked_title), + context.getString(R.string.screen_orientation_locked_summary), ), } diff --git a/RotationControl/src/main/res/values/strings.xml b/RotationControl/src/main/res/values/strings.xml index a025152..66e29ff 100644 --- a/RotationControl/src/main/res/values/strings.xml +++ b/RotationControl/src/main/res/values/strings.xml @@ -3,4 +3,38 @@ Force rotation for selected packages RotationControl Configuration Rotation Mode + UNSET + Do not override screen orientation. You might as well disable the module instead of using this option. + UNSPECIFIED + No preference specified: let the system decide the best orientation. This will either be the orientation selected by the activity below, or the user\'s preferred orientation if this activity is the bottom of a task. If the user explicitly turned off sensor based orientation through settings sensor based device rotation will be ignored. If not by default sensor based orientation will be taken into account and the orientation will changed based on how the user rotates the device. + LANDSCAPE + Would like to have the screen in a landscape orientation: that is, with the display wider than it is tall, ignoring sensor data. + PORTRAIT + Would like to have the screen in a portrait orientation: that is, with the display taller than it is wide, ignoring sensor data. + USER + Use the user\'s current preferred orientation of the handset. + BEHIND + Keep the screen in the same orientation as whatever is behind this activity. + SENSOR + Orientation is determined by a physical orientation sensor: the display will rotate based on how the user moves the device. Ignores user\'s setting to turn off sensor-based rotation. + NOSENSOR + Always ignore orientation determined by orientation sensor: the display will not rotate when the user moves the device. + SENSOR_LANDSCAPE + "Would like to have the screen in landscape orientation, but can use the sensor to change which direction the screen is facing. " + SENSOR_PORTRAIT + Would like to have the screen in portrait orientation, but can use the sensor to change which direction the screen is facing. + REVERSE_LANDSCAPE + Would like to have the screen in landscape orientation, turned in the opposite direction from normal landscape. + REVERSE_PORTRAIT + Would like to have the screen in portrait orientation, turned in the opposite direction from normal portrait. + FULL_SENSOR + Orientation is determined by a physical orientation sensor: the display will rotate based on how the user moves the device. This allows any of the 4 possible rotations, regardless of what the device will normally do (for example some devices won\'t normally use 180 degree rotation). + USER_LANDSCAPE + Would like to have the screen in landscape orientation, but if the user has enabled sensor-based rotation then we can use the sensor to change which direction the screen is facing. + USER_PORTRAIT + Would like to have the screen in portrait orientation, but if the user has enabled sensor-based rotation then we can use the sensor to change which direction the screen is facing. + FULL_USER + Respect the user\'s sensor-based rotation preference, but if sensor-based rotation is enabled then allow the screen to rotate in all 4 possible directions regardless of what the device will normally do (for example some devices won\'t normally use 180 degree rotation). + LOCKED + Screen is locked to its current rotation, whatever that is. From 2f44e3e275b5d5394bfae18672185fad7499007b Mon Sep 17 00:00:00 2001 From: programminghoch10 <16062290+programminghoch10@users.noreply.github.com> Date: Sun, 24 Aug 2025 01:26:33 +0200 Subject: [PATCH 3/5] implement rewriting orientations in RotationControl --- .../RotationControl/ROTATION_MODE.kt | 79 +++++++++++-------- .../RotationControl/RewriteOrientations.kt | 14 ++++ .../RotationControl/SettingsActivity.kt | 4 +- .../RotationControl/XposedHook.kt | 10 ++- .../src/main/res/values/strings.xml | 9 ++- .../src/main/res/xml/root_preferences.xml | 17 ++++ 6 files changed, 94 insertions(+), 39 deletions(-) create mode 100644 RotationControl/src/main/java/com/programminghoch10/RotationControl/RewriteOrientations.kt diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt index 52ae166..cff90f1 100644 --- a/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/ROTATION_MODE.kt @@ -3,7 +3,16 @@ package com.programminghoch10.RotationControl import android.app.Application import android.content.pm.ActivityInfo -val context = Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null) as Application +val context = run { + val applicationContext = Class.forName("android.app.ActivityThread").getMethod("currentApplication").invoke(null) as Application? + if (applicationContext?.packageName == BuildConfig.APPLICATION_ID) return@run applicationContext.resources + return@run null +} + +private fun getString(id: Int): String { + if (context == null) return "" + return context.getString(id) +} enum class ROTATION_MODE(val key: String, val value: Int, val title: String, val summary: String) { // yoinked from https://developer.android.com/reference/android/R.attr.html#screenOrientation @@ -11,103 +20,103 @@ enum class ROTATION_MODE(val key: String, val value: Int, val title: String, val SCREEN_ORIENTATION_UNSET( "UNSET", -2, - context.getString(R.string.screen_orientation_unset_title), - context.getString(R.string.screen_orientation_unset_summary), + getString(R.string.screen_orientation_unset_title), + getString(R.string.screen_orientation_unset_summary), ), SCREEN_ORIENTATION_UNSPECIFIED( "UNSPECIFIED", ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, - context.getString(R.string.screen_orientation_unspecified_title), - context.getString(R.string.screen_orientation_unspecified_summary), + getString(R.string.screen_orientation_unspecified_title), + getString(R.string.screen_orientation_unspecified_summary), ), SCREEN_ORIENTATION_LANDSCAPE( "LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, - context.getString(R.string.screen_orientation_landscape_title), - context.getString(R.string.screen_orientation_landscape_summary), + getString(R.string.screen_orientation_landscape_title), + getString(R.string.screen_orientation_landscape_summary), ), SCREEN_ORIENTATION_PORTRAIT( "PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, - context.getString(R.string.screen_orientation_portrait_title), - context.getString(R.string.screen_orientation_portrait_summary), + getString(R.string.screen_orientation_portrait_title), + getString(R.string.screen_orientation_portrait_summary), ), SCREEN_ORIENTATION_USER( "USER", ActivityInfo.SCREEN_ORIENTATION_USER, - context.getString(R.string.screen_orientation_user_title), - context.getString(R.string.screen_orientation_user_summary), + getString(R.string.screen_orientation_user_title), + getString(R.string.screen_orientation_user_summary), ), SCREEN_ORIENTATION_BEHIND( "BEHIND", ActivityInfo.SCREEN_ORIENTATION_BEHIND, - context.getString(R.string.screen_orientation_behind_title), - context.getString(R.string.screen_orientation_behind_summary), + getString(R.string.screen_orientation_behind_title), + getString(R.string.screen_orientation_behind_summary), ), SCREEN_ORIENTATION_SENSOR( "SENSOR", ActivityInfo.SCREEN_ORIENTATION_SENSOR, - context.getString(R.string.screen_orientation_sensor_title), - context.getString(R.string.screen_orientation_sensor_summary), + getString(R.string.screen_orientation_sensor_title), + getString(R.string.screen_orientation_sensor_summary), ), SCREEN_ORIENTATION_NOSENSOR( "NOSENSOR", ActivityInfo.SCREEN_ORIENTATION_NOSENSOR, - context.getString(R.string.screen_orientation_nosensor_title), - context.getString(R.string.screen_orientation_nosensor_summary), + getString(R.string.screen_orientation_nosensor_title), + getString(R.string.screen_orientation_nosensor_summary), ), SCREEN_ORIENTATION_SENSOR_LANDSCAPE( "SENSOR_LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, - context.getString(R.string.screen_orientation_sensor_landscape_title), - context.getString(R.string.screen_orientation_sensor_landscape_summary), + getString(R.string.screen_orientation_sensor_landscape_title), + getString(R.string.screen_orientation_sensor_landscape_summary), ), SCREEN_ORIENTATION_SENSOR_PORTRAIT( "SENSOR_PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, - context.getString(R.string.screen_orientation_sensor_portrait_title), - context.getString(R.string.screen_orientation_sensor_portrait_summary), + getString(R.string.screen_orientation_sensor_portrait_title), + getString(R.string.screen_orientation_sensor_portrait_summary), ), SCREEN_ORIENTATION_REVERSE_LANDSCAPE( "REVERSE_LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE, - context.getString(R.string.screen_orientation_reverse_landscape_title), - context.getString(R.string.screen_orientation_reverse_landscape_summary), + getString(R.string.screen_orientation_reverse_landscape_title), + getString(R.string.screen_orientation_reverse_landscape_summary), ), SCREEN_ORIENTATION_REVERSE_PORTRAIT( "REVERSE_PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT, - context.getString(R.string.screen_orientation_reverse_portrait_title), - context.getString(R.string.screen_orientation_reverse_portrait_summary), + getString(R.string.screen_orientation_reverse_portrait_title), + getString(R.string.screen_orientation_reverse_portrait_summary), ), SCREEN_ORIENTATION_FULL_SENSOR( "FULL_SENSOR", ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR, - context.getString(R.string.screen_orientation_full_sensor_title), - context.getString(R.string.screen_orientation_full_sensor_summary), + getString(R.string.screen_orientation_full_sensor_title), + getString(R.string.screen_orientation_full_sensor_summary), ), SCREEN_ORIENTATION_USER_LANDSCAPE( "USER_LANDSCAPE", ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE, - context.getString(R.string.screen_orientation_user_landscape), - context.getString(R.string.screen_orientation_user_landscape_summary), + getString(R.string.screen_orientation_user_landscape), + getString(R.string.screen_orientation_user_landscape_summary), ), SCREEN_ORIENTATION_USER_PORTRAIT( "USER_PORTRAIT", ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT, - context.getString(R.string.screen_orientation_user_portrait_title), - context.getString(R.string.screen_orientation_user_portrait_summary), + getString(R.string.screen_orientation_user_portrait_title), + getString(R.string.screen_orientation_user_portrait_summary), ), SCREEN_ORIENTATION_FULL_USER( "FULL_USER", ActivityInfo.SCREEN_ORIENTATION_FULL_USER, - context.getString(R.string.screen_orientation_full_user_title), - context.getString(R.string.screen_orientation_full_user_summary), + getString(R.string.screen_orientation_full_user_title), + getString(R.string.screen_orientation_full_user_summary), ), SCREEN_ORIENTATION_LOCKED( "LOCKED", ActivityInfo.SCREEN_ORIENTATION_LOCKED, - context.getString(R.string.screen_orientation_locked_title), - context.getString(R.string.screen_orientation_locked_summary), + getString(R.string.screen_orientation_locked_title), + getString(R.string.screen_orientation_locked_summary), ), } diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/RewriteOrientations.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/RewriteOrientations.kt new file mode 100644 index 0000000..3000a10 --- /dev/null +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/RewriteOrientations.kt @@ -0,0 +1,14 @@ +package com.programminghoch10.RotationControl + +val rewriteLockedOrientation = mapOf( + ROTATION_MODE.SCREEN_ORIENTATION_LANDSCAPE to ROTATION_MODE.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, + ROTATION_MODE.SCREEN_ORIENTATION_PORTRAIT to ROTATION_MODE.SCREEN_ORIENTATION_SENSOR_PORTRAIT, + ROTATION_MODE.SCREEN_ORIENTATION_REVERSE_LANDSCAPE to ROTATION_MODE.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, + ROTATION_MODE.SCREEN_ORIENTATION_REVERSE_PORTRAIT to ROTATION_MODE.SCREEN_ORIENTATION_SENSOR_PORTRAIT, +) + +val rewriteSensorOrientation = mapOf( + ROTATION_MODE.SCREEN_ORIENTATION_SENSOR to ROTATION_MODE.SCREEN_ORIENTATION_FULL_SENSOR, + ROTATION_MODE.SCREEN_ORIENTATION_USER to ROTATION_MODE.SCREEN_ORIENTATION_FULL_USER, +) + diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt index 9827548..991ec81 100644 --- a/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt @@ -31,9 +31,9 @@ class SettingsActivity : FragmentActivity() { @SuppressLint("WorldReadableFiles") override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - setPreferencesFromResource(R.xml.root_preferences, rootKey) preferenceManager.sharedPreferencesName = SHARED_PREFERENCES_NAME preferenceManager.sharedPreferencesMode = MODE_WORLD_READABLE + setPreferencesFromResource(R.xml.root_preferences, rootKey) val preferenceCategory = findPreference("category_rotation_mode")!! val context = requireContext() @@ -49,6 +49,8 @@ class SettingsActivity : FragmentActivity() { true } preferenceCategory.addPreference(preference) + if (rotationMode in rewriteLockedOrientation.keys) preference.dependency = "rewrite_locked_orientations" + if (rotationMode in rewriteSensorOrientation.keys) preference.dependency = "rewrite_sensor_orientations" } } } diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt index b7985c5..03fde61 100644 --- a/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/XposedHook.kt @@ -21,8 +21,16 @@ class XposedHook : IXposedHookLoadPackage { Int::class.java, object : XC_MethodHook() { override fun beforeHookedMethod(param: MethodHookParam) { + val originalRotationMode = ROTATION_MODE.entries.find { it.value == param.args[0] } ?: ROTATION_MODE.SCREEN_ORIENTATION_UNSET val sharedPreferences: SharedPreferences = XSharedPreferences(BuildConfig.APPLICATION_ID, SHARED_PREFERENCES_NAME) - val selectedRotationMode = ROTATION_MODE.entries.find { sharedPreferences.getBoolean(it.key, false) } ?: ROTATION_MODE_DEFAULT + var selectedRotationMode = ROTATION_MODE.entries.find { sharedPreferences.getBoolean(it.key, false) } ?: ROTATION_MODE_DEFAULT + if (selectedRotationMode == ROTATION_MODE.SCREEN_ORIENTATION_UNSET) selectedRotationMode = originalRotationMode + if (sharedPreferences.getBoolean("rewrite_locked_orientations", false)) { + selectedRotationMode = rewriteLockedOrientation.get(selectedRotationMode) ?: selectedRotationMode + } + if (sharedPreferences.getBoolean("rewrite_sensor_orientations", false)) { + selectedRotationMode = rewriteSensorOrientation.get(selectedRotationMode) ?: selectedRotationMode + } if (selectedRotationMode == ROTATION_MODE.SCREEN_ORIENTATION_UNSET) return param.args[0] = selectedRotationMode.value } diff --git a/RotationControl/src/main/res/values/strings.xml b/RotationControl/src/main/res/values/strings.xml index 66e29ff..f7a4503 100644 --- a/RotationControl/src/main/res/values/strings.xml +++ b/RotationControl/src/main/res/values/strings.xml @@ -2,9 +2,9 @@ RotationControl Force rotation for selected packages RotationControl Configuration - Rotation Mode + Forced Rotation Mode UNSET - Do not override screen orientation. You might as well disable the module instead of using this option. + Do not override screen orientation. Use this option if you only want to use the rewrite functionality above. UNSPECIFIED No preference specified: let the system decide the best orientation. This will either be the orientation selected by the activity below, or the user\'s preferred orientation if this activity is the bottom of a task. If the user explicitly turned off sensor based orientation through settings sensor based device rotation will be ignored. If not by default sensor based orientation will be taken into account and the orientation will changed based on how the user rotates the device. LANDSCAPE @@ -37,4 +37,9 @@ Respect the user\'s sensor-based rotation preference, but if sensor-based rotation is enabled then allow the screen to rotate in all 4 possible directions regardless of what the device will normally do (for example some devices won\'t normally use 180 degree rotation). LOCKED Screen is locked to its current rotation, whatever that is. + Rewrite to sensor orientation + Rewrite locked orientations to sensor orientations. + Force full sensor rotation + Rewrite sensor orientations to full sensor orientations. + Rewrite Options diff --git a/RotationControl/src/main/res/xml/root_preferences.xml b/RotationControl/src/main/res/xml/root_preferences.xml index 3e89b30..0166d64 100644 --- a/RotationControl/src/main/res/xml/root_preferences.xml +++ b/RotationControl/src/main/res/xml/root_preferences.xml @@ -1,5 +1,22 @@ + + + + + + From 5a22a8cd3bd80ed212d441530091a97204bc20a8 Mon Sep 17 00:00:00 2001 From: programminghoch10 <16062290+programminghoch10@users.noreply.github.com> Date: Sun, 24 Aug 2025 01:27:27 +0200 Subject: [PATCH 4/5] change default RotationControl orientation mode to SENSOR --- .../programminghoch10/RotationControl/SettingsActivity.kt | 2 +- RotationControl/src/main/res/xml/root_preferences.xml | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt index 991ec81..4a32653 100644 --- a/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt @@ -7,7 +7,7 @@ import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat -val ROTATION_MODE_DEFAULT = ROTATION_MODE.SCREEN_ORIENTATION_FULL_SENSOR +val ROTATION_MODE_DEFAULT = ROTATION_MODE.SCREEN_ORIENTATION_SENSOR const val SHARED_PREFERENCES_NAME = "rotation_mode" class SettingsActivity : FragmentActivity() { diff --git a/RotationControl/src/main/res/xml/root_preferences.xml b/RotationControl/src/main/res/xml/root_preferences.xml index 0166d64..d4e59b8 100644 --- a/RotationControl/src/main/res/xml/root_preferences.xml +++ b/RotationControl/src/main/res/xml/root_preferences.xml @@ -1,14 +1,13 @@ - + - + - + From bec843aa0ff09bd8733d297a4a32e4231658e69b Mon Sep 17 00:00:00 2001 From: programminghoch10 <16062290+programminghoch10@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:02:04 +0200 Subject: [PATCH 5/5] remove reserved icon space from RotationControl settings activity preferences --- .../RotationControl/SettingsActivity.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt b/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt index 4a32653..7c2d840 100644 --- a/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt +++ b/RotationControl/src/main/java/com/programminghoch10/RotationControl/SettingsActivity.kt @@ -6,6 +6,8 @@ import androidx.fragment.app.FragmentActivity import androidx.preference.Preference import androidx.preference.PreferenceCategory import androidx.preference.PreferenceFragmentCompat +import androidx.preference.PreferenceGroup +import androidx.preference.children val ROTATION_MODE_DEFAULT = ROTATION_MODE.SCREEN_ORIENTATION_SENSOR const val SHARED_PREFERENCES_NAME = "rotation_mode" @@ -52,6 +54,13 @@ class SettingsActivity : FragmentActivity() { if (rotationMode in rewriteLockedOrientation.keys) preference.dependency = "rewrite_locked_orientations" if (rotationMode in rewriteSensorOrientation.keys) preference.dependency = "rewrite_sensor_orientations" } + + preferenceScreen.setIconSpaceReservedRecursive() + } + + private fun Preference.setIconSpaceReservedRecursive(iconSpaceReserved: Boolean = false) { + this.isIconSpaceReserved = iconSpaceReserved + if (this is PreferenceGroup) this.children.forEach { it.setIconSpaceReservedRecursive(iconSpaceReserved) } } } }