mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-10-14 19:27:09 -04:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fcf38833ab | ||
|
|
265e3249d8 | ||
|
|
e95ba8d8a2 | ||
|
|
155cbbb894 | ||
|
|
4fd326bd01 |
No files matched your search
@@ -283,12 +283,20 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
private var secondScreenDisplays by mutableStateOf<List<SecondScreenDisplay>>(emptyList())
|
||||
private var selectedSecondScreenDisplay by mutableStateOf(SessionState.secondScreenDisplay)
|
||||
private var started = false
|
||||
private var sessionActivityDisplayId = Display.DEFAULT_DISPLAY
|
||||
private lateinit var displayManager: DisplayManager
|
||||
private var secondScreenPresentation: SecondScreenPresentation? = null
|
||||
private val displayListener = object : DisplayManager.DisplayListener {
|
||||
override fun onDisplayAdded(displayId: Int) = refreshSecondScreenDisplays()
|
||||
override fun onDisplayRemoved(displayId: Int) = refreshSecondScreenDisplays()
|
||||
override fun onDisplayAdded(displayId: Int) {
|
||||
notifyActivityDisplayStateChanged(displayId)
|
||||
refreshSecondScreenDisplays()
|
||||
}
|
||||
override fun onDisplayRemoved(displayId: Int) {
|
||||
notifyActivityDisplayStateChanged(displayId)
|
||||
refreshSecondScreenDisplays()
|
||||
}
|
||||
override fun onDisplayChanged(displayId: Int) {
|
||||
notifyActivityDisplayStateChanged(displayId)
|
||||
followPanelRefresh(displayId)
|
||||
refreshSecondScreenDisplays()
|
||||
}
|
||||
@@ -1283,6 +1291,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
intent.getStringExtra(SessionService.EXTRA_STEAM_UI),
|
||||
intent.getStringExtra(SessionService.EXTRA_STEAM_URL),
|
||||
intent.getStringArrayExtra(SessionService.EXTRA_PROGRAM_ARGS),
|
||||
activityDisplayId = sessionActivityDisplayId,
|
||||
)
|
||||
}
|
||||
applyFrameGen()
|
||||
@@ -1330,6 +1339,9 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
|
||||
override fun onConfigurationChanged(newConfig: android.content.res.Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
if (refreshActivityDisplayId() && started) {
|
||||
SessionService.activityDisplayChanged(this, sessionActivityDisplayId)
|
||||
}
|
||||
applyFollowOrientation(newConfig)
|
||||
applyUnfoldedControls()
|
||||
}
|
||||
@@ -1768,7 +1780,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
|
||||
private fun refreshSecondScreenDisplays() {
|
||||
if (!::displayManager.isInitialized) return
|
||||
val primaryId = display?.displayId ?: windowManager.defaultDisplay.displayId
|
||||
val primaryId = windowManager.defaultDisplay.displayId
|
||||
val candidates = SecondScreenDisplays.available(displayManager, primaryId)
|
||||
val oldIds = secondScreenDisplays.map { it.id }.toSet()
|
||||
secondScreenDisplays = candidates
|
||||
@@ -1782,6 +1794,24 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
else if (started && secondScreenMode != SecondScreenMode.NONE && secondScreenPresentation == null) showSecondScreen(secondScreenMode)
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun currentActivityDisplayId(): Int = windowManager.defaultDisplay.displayId
|
||||
|
||||
private fun refreshActivityDisplayId(): Boolean {
|
||||
val current = currentActivityDisplayId()
|
||||
val changed = sessionActivityDisplayId != current
|
||||
sessionActivityDisplayId = current
|
||||
SessionState.activityDisplayId = current
|
||||
return changed
|
||||
}
|
||||
|
||||
private fun notifyActivityDisplayStateChanged(changedDisplayId: Int) {
|
||||
val changed = refreshActivityDisplayId()
|
||||
if (started && (changed || changedDisplayId == sessionActivityDisplayId)) {
|
||||
SessionService.activityDisplayChanged(this, sessionActivityDisplayId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectSecondScreenDisplay(displayId: Int) {
|
||||
if (secondScreenDisplays.none { it.id == displayId }) return
|
||||
selectedSecondScreenDisplay = displayId
|
||||
@@ -2222,10 +2252,11 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
super.onStart()
|
||||
if (runtimeRemovalBlocked) return
|
||||
started = true
|
||||
refreshActivityDisplayId()
|
||||
displayManager.registerDisplayListener(displayListener, Handler(Looper.getMainLooper()))
|
||||
refreshSecondScreenDisplays()
|
||||
if (secondScreenMode != SecondScreenMode.NONE && secondScreenPresentation == null) showSecondScreen(secondScreenMode)
|
||||
SessionService.setActivityVisible(this, true)
|
||||
SessionService.setActivityVisible(this, true, sessionActivityDisplayId)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
@@ -2233,7 +2264,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
started = false
|
||||
displayManager.unregisterDisplayListener(displayListener)
|
||||
closeSecondScreen(reset = false)
|
||||
SessionService.setActivityVisible(this, false)
|
||||
SessionService.setActivityVisible(this, false, sessionActivityDisplayId)
|
||||
super.onStop()
|
||||
}
|
||||
|
||||
@@ -2260,6 +2291,9 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
if (refreshActivityDisplayId() && started) {
|
||||
SessionService.activityDisplayChanged(this, sessionActivityDisplayId)
|
||||
}
|
||||
applyFollowOrientation(resources.configuration)
|
||||
if (runtimeRemovalBlocked) return
|
||||
com.droiddeck.launcher.ui.Motion.refresh(this)
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.content.BroadcastReceiver
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.net.TrafficStats
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
@@ -22,6 +23,7 @@ import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.PowerManager
|
||||
import android.util.Log
|
||||
import android.view.Display
|
||||
import com.droiddeck.launcher.R
|
||||
import com.droiddeck.launcher.SessionActivity
|
||||
import com.droiddeck.launcher.audio.DirectAudioRelayComponent
|
||||
@@ -71,7 +73,9 @@ class SessionService : Service() {
|
||||
private var suspendPolicy = SessionPrefs.SUSPEND_MANUAL
|
||||
private var steamDownloadsInBackground = false
|
||||
private var activityVisible = true
|
||||
private var activityDisplayId = Display.DEFAULT_DISPLAY
|
||||
private var screenOn = true
|
||||
private var previouslyHidden: Boolean? = null
|
||||
private var manualPauseRequested = false
|
||||
private var steamSleepToken: String? = null
|
||||
private var nativeSleepToken: String? = null
|
||||
@@ -94,7 +98,6 @@ class SessionService : Service() {
|
||||
Intent.ACTION_SCREEN_ON -> screenOn = true
|
||||
else -> return
|
||||
}
|
||||
if (screenOn) resumeSteamSleepOnReturn()
|
||||
suspendAttemptFailed = false
|
||||
updateSuspendPolicy()
|
||||
}
|
||||
@@ -156,20 +159,27 @@ class SessionService : Service() {
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
ACTION_ACTIVITY_VISIBLE -> {
|
||||
activityDisplayId = intent.getIntExtra(EXTRA_ACTIVITY_DISPLAY_ID, activityDisplayId)
|
||||
if (!SessionState.pipActive) pipTask = false
|
||||
activityVisible = true
|
||||
suspendDownloadNow = false
|
||||
resumeSteamSleepOnReturn()
|
||||
suspendAttemptFailed = false
|
||||
updateSuspendPolicy()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
ACTION_ACTIVITY_HIDDEN -> {
|
||||
activityDisplayId = intent.getIntExtra(EXTRA_ACTIVITY_DISPLAY_ID, activityDisplayId)
|
||||
activityVisible = false
|
||||
suspendAttemptFailed = false
|
||||
updateSuspendPolicy()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
ACTION_ACTIVITY_DISPLAY_CHANGED -> {
|
||||
activityDisplayId = intent.getIntExtra(EXTRA_ACTIVITY_DISPLAY_ID, activityDisplayId)
|
||||
suspendAttemptFailed = false
|
||||
updateSuspendPolicy()
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
ACTION_SUSPEND_POLICY_CHANGED -> {
|
||||
if (!SessionState.running) return START_NOT_STICKY
|
||||
suspendPolicy = SessionPrefs.suspendPolicy(this, SessionState.mode)
|
||||
@@ -205,7 +215,9 @@ class SessionService : Service() {
|
||||
suspendPolicy = SessionPrefs.suspendPolicy(this, SessionState.mode)
|
||||
steamDownloadsInBackground = SessionPrefs.steamDownloadsInBackground(this)
|
||||
activityVisible = true
|
||||
activityDisplayId = SessionState.activityDisplayId
|
||||
screenOn = (getSystemService(Context.POWER_SERVICE) as? PowerManager)?.isInteractive ?: true
|
||||
previouslyHidden = null
|
||||
manualPauseRequested = false
|
||||
suspendDownloadNow = false
|
||||
steamDownloadMonitor.reset()
|
||||
@@ -1105,11 +1117,22 @@ class SessionService : Service() {
|
||||
|
||||
private fun updateSuspendPolicy() {
|
||||
if (!SessionState.running) return
|
||||
if (suspendPolicy == SessionPrefs.SUSPEND_MANUAL && (!activityVisible || !screenOn)) {
|
||||
val activityDisplayOn = activityDisplayOn()
|
||||
val hidden = SessionVisibilityPolicy.isHidden(
|
||||
activityStarted = activityVisible,
|
||||
screenOn = screenOn,
|
||||
activityOnDefaultDisplay = activityDisplayId == Display.DEFAULT_DISPLAY,
|
||||
activityDisplayOn = activityDisplayOn,
|
||||
)
|
||||
val wasHidden = previouslyHidden
|
||||
previouslyHidden = hidden
|
||||
if (SessionVisibilityPolicy.shouldResumeOnVisibleTransition(wasHidden, hidden, suspendPolicy)) {
|
||||
resumeSteamSleepOnReturn()
|
||||
}
|
||||
if (suspendPolicy == SessionPrefs.SUSPEND_MANUAL && hidden) {
|
||||
manualPauseRequested = true
|
||||
}
|
||||
val controller = suspendController ?: return
|
||||
val hidden = !activityVisible || !screenOn
|
||||
val downloadsBlockingSuspend = steamDownloadsInBackground && SessionState.mode == MODE_STEAM &&
|
||||
suspendPolicy != SessionPrefs.SUSPEND_NEVER && hidden && downloadActive && !suspendDownloadNow
|
||||
if (downloadsBlockingSuspend) acquireLocks()
|
||||
@@ -1130,7 +1153,9 @@ class SessionService : Service() {
|
||||
suspendOperationPending = true
|
||||
SessionEvents.record(if (shouldSuspend) "session.suspend_requested" else "session.resume_requested", mapOf(
|
||||
"policy" to suspendPolicy, "activityVisible" to activityVisible,
|
||||
"screenOn" to screenOn, "steamSleep" to (steamSleepToken != null),
|
||||
"screenOn" to screenOn, "activityDisplayId" to activityDisplayId,
|
||||
"activityDisplayOn" to activityDisplayOn, "activityHidden" to hidden,
|
||||
"steamSleep" to (steamSleepToken != null),
|
||||
"nativeSleep" to (nativeSleepToken != null),
|
||||
))
|
||||
if (shouldSuspend) {
|
||||
@@ -1188,13 +1213,25 @@ class SessionService : Service() {
|
||||
}
|
||||
|
||||
private fun resumeSteamSleepOnReturn() {
|
||||
if (suspendPolicy in setOf(SessionPrefs.SUSPEND_AUTO, SessionPrefs.SUSPEND_NATIVE) && activityVisible && screenOn) {
|
||||
val visible = !SessionVisibilityPolicy.isHidden(
|
||||
activityStarted = activityVisible,
|
||||
screenOn = screenOn,
|
||||
activityOnDefaultDisplay = activityDisplayId == Display.DEFAULT_DISPLAY,
|
||||
activityDisplayOn = activityDisplayOn(),
|
||||
)
|
||||
if (suspendPolicy in setOf(SessionPrefs.SUSPEND_AUTO, SessionPrefs.SUSPEND_NATIVE) && visible) {
|
||||
if (steamSleepToken == null && (nativeSleepToken == null || nativeSleepFallback)) requestSteamWake()
|
||||
completeNativeSleep()
|
||||
completeSteamSleep()
|
||||
}
|
||||
}
|
||||
|
||||
private fun activityDisplayOn(): Boolean {
|
||||
if (activityDisplayId == Display.DEFAULT_DISPLAY) return screenOn
|
||||
val displays = getSystemService(Context.DISPLAY_SERVICE) as? DisplayManager ?: return false
|
||||
return displays.getDisplay(activityDisplayId)?.state == Display.STATE_ON
|
||||
}
|
||||
|
||||
private fun prepareNativeSleep() {
|
||||
val token = UUID.randomUUID().toString().replace("-", "")
|
||||
nativeSleepToken = token
|
||||
@@ -1553,6 +1590,7 @@ class SessionService : Service() {
|
||||
private const val ACTION_SUSPEND_POLICY_CHANGED = "com.droiddeck.launcher.SUSPEND_POLICY_CHANGED"
|
||||
private const val ACTION_ACTIVITY_VISIBLE = "com.droiddeck.launcher.ACTIVITY_VISIBLE"
|
||||
private const val ACTION_ACTIVITY_HIDDEN = "com.droiddeck.launcher.ACTIVITY_HIDDEN"
|
||||
private const val ACTION_ACTIVITY_DISPLAY_CHANGED = "com.droiddeck.launcher.ACTIVITY_DISPLAY_CHANGED"
|
||||
private const val ACTION_TRACK_AUXILIARY = "com.droiddeck.launcher.TRACK_AUXILIARY"
|
||||
private const val ACTION_STOP_AUXILIARY = "com.droiddeck.launcher.STOP_AUXILIARY"
|
||||
private const val ACTION_AUXILIARY_EXITED = "com.droiddeck.launcher.AUXILIARY_EXITED"
|
||||
@@ -1580,11 +1618,14 @@ class SessionService : Service() {
|
||||
const val EXTRA_STEAM_UI = "steamUi"
|
||||
const val EXTRA_STEAM_URL = "steamUrl"
|
||||
const val EXTRA_GAME_ID = "gameId"
|
||||
private const val EXTRA_ACTIVITY_DISPLAY_ID = "activityDisplayId"
|
||||
|
||||
fun start(
|
||||
context: Context, mode: String = MODE_STEAM, program: String? = null,
|
||||
steamUi: String? = null, steamUrl: String? = null, programArgs: Array<String>? = null,
|
||||
activityDisplayId: Int = Display.DEFAULT_DISPLAY,
|
||||
) {
|
||||
SessionState.activityDisplayId = activityDisplayId
|
||||
val intent = Intent(context, SessionService::class.java).putExtra(EXTRA_MODE, mode)
|
||||
if (program != null) intent.putExtra(EXTRA_PROGRAM, program)
|
||||
if (programArgs != null) intent.putExtra(EXTRA_PROGRAM_ARGS, programArgs)
|
||||
@@ -1606,10 +1647,31 @@ class SessionService : Service() {
|
||||
context.startService(Intent(context, SessionService::class.java).setAction(ACTION_PIP_BEGIN))
|
||||
}
|
||||
|
||||
fun setActivityVisible(context: Context, visible: Boolean) {
|
||||
fun setActivityVisible(
|
||||
context: Context,
|
||||
visible: Boolean,
|
||||
activityDisplayId: Int = currentActivityDisplayId(context),
|
||||
) {
|
||||
SessionState.activityDisplayId = activityDisplayId
|
||||
if (!SessionState.running) return
|
||||
val action = if (visible) ACTION_ACTIVITY_VISIBLE else ACTION_ACTIVITY_HIDDEN
|
||||
context.startService(Intent(context, SessionService::class.java).setAction(action))
|
||||
context.startService(Intent(context, SessionService::class.java)
|
||||
.setAction(action)
|
||||
.putExtra(EXTRA_ACTIVITY_DISPLAY_ID, activityDisplayId))
|
||||
}
|
||||
|
||||
fun activityDisplayChanged(context: Context, activityDisplayId: Int) {
|
||||
SessionState.activityDisplayId = activityDisplayId
|
||||
if (!SessionState.running) return
|
||||
context.startService(Intent(context, SessionService::class.java)
|
||||
.setAction(ACTION_ACTIVITY_DISPLAY_CHANGED)
|
||||
.putExtra(EXTRA_ACTIVITY_DISPLAY_ID, activityDisplayId))
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun currentActivityDisplayId(context: Context): Int {
|
||||
val activity = context as? android.app.Activity ?: return Display.DEFAULT_DISPLAY
|
||||
return activity.windowManager.defaultDisplay.displayId
|
||||
}
|
||||
|
||||
fun resume(context: Context) {
|
||||
|
||||
@@ -41,6 +41,8 @@ object SessionState {
|
||||
|
||||
@Volatile
|
||||
var running = false
|
||||
@Volatile
|
||||
var activityDisplayId = 0
|
||||
var suspended by mutableStateOf(false)
|
||||
@Volatile var pipActive = false
|
||||
@Volatile
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.droiddeck.launcher.session
|
||||
|
||||
internal object SessionVisibilityPolicy {
|
||||
fun isHidden(
|
||||
activityStarted: Boolean,
|
||||
screenOn: Boolean,
|
||||
activityOnDefaultDisplay: Boolean,
|
||||
activityDisplayOn: Boolean,
|
||||
): Boolean = !activityStarted || if (activityOnDefaultDisplay) !screenOn else !activityDisplayOn
|
||||
|
||||
fun shouldResumeOnVisibleTransition(
|
||||
previouslyHidden: Boolean?,
|
||||
currentlyHidden: Boolean,
|
||||
suspendPolicy: String,
|
||||
): Boolean = previouslyHidden == true && !currentlyHidden &&
|
||||
suspendPolicy in setOf(SessionPrefs.SUSPEND_AUTO, SessionPrefs.SUSPEND_NATIVE)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.droiddeck.launcher.session
|
||||
|
||||
import android.app.Activity
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [26, 28, 29, 33], manifest = Config.NONE)
|
||||
class ActivityDisplayCompatibilityTest {
|
||||
@Test fun visibleActivityUsesItsDisplayIdAcrossSupportedAndroidVersions() {
|
||||
val wasRunning = SessionState.running
|
||||
val previousDisplayId = SessionState.activityDisplayId
|
||||
val activity = Robolectric.buildActivity(Activity::class.java).setup().get()
|
||||
try {
|
||||
SessionState.running = false
|
||||
SessionService.setActivityVisible(activity, true)
|
||||
|
||||
assertEquals(activity.windowManager.defaultDisplay.displayId, SessionState.activityDisplayId)
|
||||
} finally {
|
||||
SessionState.running = wasRunning
|
||||
SessionState.activityDisplayId = previousDisplayId
|
||||
activity.finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package com.droiddeck.launcher.session
|
||||
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
|
||||
class SessionVisibilityPolicyTest {
|
||||
@Test fun handsetScreenLockHidesActivityOnDefaultDisplay() {
|
||||
assertFalse(SessionVisibilityPolicy.isHidden(true, true, true, true))
|
||||
assertTrue(SessionVisibilityPolicy.isHidden(true, false, true, true))
|
||||
}
|
||||
|
||||
@Test fun handsetScreenOffDoesNotHideActivityOnPoweredOnDexDisplay() {
|
||||
assertFalse(SessionVisibilityPolicy.isHidden(true, false, false, true))
|
||||
}
|
||||
|
||||
@Test fun externalDisplayOffHidesActivityEvenWhenHandsetIsOn() {
|
||||
assertTrue(SessionVisibilityPolicy.isHidden(true, true, false, false))
|
||||
}
|
||||
|
||||
@Test fun disconnectedExternalDisplayIsHidden() {
|
||||
assertTrue(SessionVisibilityPolicy.isHidden(true, false, false, false))
|
||||
}
|
||||
|
||||
@Test fun hiddenExternalActivityIsHiddenWhileItsDisplayIsOn() {
|
||||
assertTrue(SessionVisibilityPolicy.isHidden(false, false, false, true))
|
||||
}
|
||||
|
||||
@Test fun startedButUnfocusedMultiwindowActivityRemainsVisible() {
|
||||
assertFalse(SessionVisibilityPolicy.isHidden(true, true, true, true))
|
||||
}
|
||||
|
||||
@Test fun defaultDisplayScreenOnResumesAfterScreenOff() {
|
||||
val wasHidden = SessionVisibilityPolicy.isHidden(true, false, true, true)
|
||||
val isHidden = SessionVisibilityPolicy.isHidden(true, true, true, true)
|
||||
assertTrue(SessionVisibilityPolicy.shouldResumeOnVisibleTransition(
|
||||
previouslyHidden = wasHidden,
|
||||
currentlyHidden = isHidden,
|
||||
suspendPolicy = SessionPrefs.SUSPEND_AUTO,
|
||||
))
|
||||
}
|
||||
|
||||
@Test fun externalDisplayOnResumesAfterOffOrDisconnect() {
|
||||
val wasHidden = SessionVisibilityPolicy.isHidden(true, false, false, false)
|
||||
val isHidden = SessionVisibilityPolicy.isHidden(true, false, false, true)
|
||||
assertTrue(SessionVisibilityPolicy.shouldResumeOnVisibleTransition(
|
||||
previouslyHidden = wasHidden,
|
||||
currentlyHidden = isHidden,
|
||||
suspendPolicy = SessionPrefs.SUSPEND_NATIVE,
|
||||
))
|
||||
}
|
||||
|
||||
@Test fun startedActivityResumesAfterBeingStopped() {
|
||||
val wasHidden = SessionVisibilityPolicy.isHidden(false, false, false, true)
|
||||
val isHidden = SessionVisibilityPolicy.isHidden(true, false, false, true)
|
||||
assertTrue(SessionVisibilityPolicy.shouldResumeOnVisibleTransition(
|
||||
previouslyHidden = wasHidden,
|
||||
currentlyHidden = isHidden,
|
||||
suspendPolicy = SessionPrefs.SUSPEND_AUTO,
|
||||
))
|
||||
}
|
||||
|
||||
@Test fun onToOnDisplayPropertyChangeDoesNotResume() {
|
||||
val wasHidden = SessionVisibilityPolicy.isHidden(true, true, false, true)
|
||||
val isHidden = SessionVisibilityPolicy.isHidden(true, true, false, true)
|
||||
assertFalse(SessionVisibilityPolicy.shouldResumeOnVisibleTransition(
|
||||
previouslyHidden = wasHidden,
|
||||
currentlyHidden = isHidden,
|
||||
suspendPolicy = SessionPrefs.SUSPEND_AUTO,
|
||||
))
|
||||
assertFalse(SessionVisibilityPolicy.shouldResumeOnVisibleTransition(
|
||||
previouslyHidden = null,
|
||||
currentlyHidden = isHidden,
|
||||
suspendPolicy = SessionPrefs.SUSPEND_AUTO,
|
||||
))
|
||||
}
|
||||
|
||||
@Test fun handsetScreenOnDoesNotResumeVisibleExternalDisplay() {
|
||||
val wasHidden = SessionVisibilityPolicy.isHidden(true, false, false, true)
|
||||
val isHidden = SessionVisibilityPolicy.isHidden(true, true, false, true)
|
||||
assertFalse(SessionVisibilityPolicy.shouldResumeOnVisibleTransition(
|
||||
previouslyHidden = wasHidden,
|
||||
currentlyHidden = isHidden,
|
||||
suspendPolicy = SessionPrefs.SUSPEND_AUTO,
|
||||
))
|
||||
}
|
||||
|
||||
@Test fun manualPolicyDoesNotResumeOnVisibleTransition() {
|
||||
val wasHidden = SessionVisibilityPolicy.isHidden(true, false, true, true)
|
||||
val isHidden = SessionVisibilityPolicy.isHidden(true, true, true, true)
|
||||
assertFalse(SessionVisibilityPolicy.shouldResumeOnVisibleTransition(
|
||||
previouslyHidden = wasHidden,
|
||||
currentlyHidden = isHidden,
|
||||
suspendPolicy = SessionPrefs.SUSPEND_MANUAL,
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -11,20 +11,8 @@ diff --git a/src/syscall/seccomp.c b/src/syscall/seccomp.c
|
||||
index ee7b8acd68660f38fd52f56e951ffb94e9061d68..ff3a79b60e9092a296bb444c919bb3861338727f 100644
|
||||
--- a/src/syscall/seccomp.c
|
||||
+++ b/src/syscall/seccomp.c
|
||||
@@ -738,4 +738,4 @@ int enable_syscall_filtering(const Tracee *tracee)
|
||||
- * the statx one emulates the call when it fails, which only a kernel
|
||||
- * before 4.11 does for want of it - a statx Android's policy traps is
|
||||
- * emulated from SIGSYS instead. Both stops re-read and re-translate
|
||||
- * the path, and are paid on every call.
|
||||
+ * the statx one emulates the syscall before 4.11 and supplies MNT_ID
|
||||
+ * from fdinfo through 5.7. Android policy traps are still emulated from
|
||||
+ * SIGSYS instead. Both stops re-read and re-translate the path, and are
|
||||
+ * paid on every call.
|
||||
@@ -764 +764,4 @@ static void drop_unneeded_exit_stops(void)
|
||||
@@ -764 +764 @@ static void drop_unneeded_exit_stops(void)
|
||||
- if (major > 4 || (major == 4 && minor >= 11))
|
||||
+ /* Linux 4.11 introduced statx; Linux 5.8 added MNT_ID.
|
||||
+ * Keep its exit stop through 5.7 so the missing ID can be
|
||||
+ * recovered from the descriptor's fdinfo. */
|
||||
+ if (major > 5 || (major == 5 && minor >= 8))
|
||||
diff --git a/src/tracee/statx.c b/src/tracee/statx.c
|
||||
index ca972f892e84461cb694dd13a37bfbc67527b320..824771ccf5934e1f870fc36a29fb22fdcad0a856 100644
|
||||
@@ -32,11 +20,7 @@ index ca972f892e84461cb694dd13a37bfbc67527b320..824771ccf5934e1f870fc36a29fb22fd
|
||||
+++ b/src/tracee/statx.c
|
||||
@@ -4,0 +5 @@
|
||||
+#include "tracee/statx_mnt_id.h"
|
||||
@@ -125,0 +127,9 @@ int handle_statx_syscall(Tracee *tracee, bool from_sigsys) {
|
||||
+ /* libglnx chases an already-open fd with AT_EMPTY_PATH and requires a
|
||||
+ * mount ID. Kernels before 5.8 can succeed without returning that field.
|
||||
+ * The tracee is stopped at this syscall exit; accept only the ordinary
|
||||
+ * mount ID and verify the fdinfo inode against the statx result. */
|
||||
@@ -125,0 +127,5 @@ int handle_statx_syscall(Tracee *tracee, bool from_sigsys) {
|
||||
+ if (droiddeck_proot_statx_fill_mnt_id(tracee->pid, (int) dirfd,
|
||||
+ (int) flags, guest_path, (unsigned int) mask,
|
||||
+ &state.statx_buf))
|
||||
|
||||
Reference in new issue
Block a user