Skip to content

Commit

Permalink
Refactor: Move TileService startForegroundService() workaround to one
Browse files Browse the repository at this point in the history
function

Bug: #1238
  • Loading branch information
zhanghai committed Jun 26, 2024
1 parent c9fd16e commit 7a2b228
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,57 @@

package me.zhanghai.android.files.compat

import android.graphics.PixelFormat
import android.os.Build
import android.os.IBinder
import android.service.quicksettings.TileService
import android.view.View
import android.view.WindowManager
import androidx.annotation.RequiresApi
import androidx.core.view.doOnPreDraw
import me.zhanghai.android.files.hiddenapi.RestrictedHiddenApi
import me.zhanghai.android.files.util.lazyReflectedField

// Work around https://issuetracker.google.com/issues/299506164 on U which is fixed in V.
fun TileService.doWithStartForegroundServiceAllowed(action: () -> Unit) {
if (Build.VERSION.SDK_INT != Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
action()
return
}
val windowManager = getSystemService(WindowManager::class.java)
val view = View(this)
val layoutParams =
WindowManager.LayoutParams().apply {
type = WindowManager_LayoutParams_TYPE_QS_DIALOG
format = PixelFormat.TRANSLUCENT
token = this@doWithStartForegroundServiceAllowed.token
}
windowManager.addView(view, layoutParams)
// We need to wait for WindowState.onSurfaceShownChanged(), basically when the first draw has
// finished and the surface is about to be shown to the user. However there's no good callback
// for that, while waiting for the second pre-draw seems to work.
view.doOnPreDraw {
view.post {
view.invalidate()
view.doOnPreDraw {
try {
action()
} finally {
windowManager.removeView(view)
}
}
}
}
}

private const val WindowManager_LayoutParams_TYPE_QS_DIALOG =
WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW + 35

@delegate:RequiresApi(Build.VERSION_CODES.N)
@get:RequiresApi(Build.VERSION_CODES.N)
@RestrictedHiddenApi
private val tokenField by lazyReflectedField(TileService::class.qualifiedName!!, "mToken")

val TileService.token: IBinder?
private val TileService.token: IBinder?
@RequiresApi(Build.VERSION_CODES.N)
get() = tokenField.get(this) as IBinder?

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,12 @@

package me.zhanghai.android.files.ftpserver

import android.graphics.PixelFormat
import android.os.Build
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import android.view.View
import android.view.WindowManager
import androidx.annotation.RequiresApi
import androidx.core.view.doOnPreDraw
import androidx.lifecycle.Observer
import me.zhanghai.android.files.compat.WindowManagerLayoutParamsCompat
import me.zhanghai.android.files.compat.token
import me.zhanghai.android.files.compat.doWithStartForegroundServiceAllowed

@RequiresApi(Build.VERSION_CODES.N)
class FtpServerTileService : TileService() {
Expand Down Expand Up @@ -55,39 +50,6 @@ class FtpServerTileService : TileService() {
}

private fun toggle() {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
runWithForegroundWindow { FtpServerService.toggle(this) }
} else {
FtpServerService.toggle(this)
}
}

// Work around https://issuetracker.google.com/issues/299506164 on U which is fixed in V.
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
private fun runWithForegroundWindow(block: () -> Unit) {
val windowManager = getSystemService(WindowManager::class.java)
val view = View(this)
val layoutParams =
WindowManager.LayoutParams().apply {
type = WindowManagerLayoutParamsCompat.TYPE_QS_DIALOG
format = PixelFormat.TRANSLUCENT
token = this@FtpServerTileService.token
}
windowManager.addView(view, layoutParams)
// We need to wait for WindowState.onSurfaceShownChanged(), basically when the first draw
// has finished and the surface is about to be shown to the user. However there's no good
// callback for that, while waiting for the second pre-draw seems to work.
view.doOnPreDraw {
view.post {
view.invalidate()
view.doOnPreDraw {
try {
block()
} finally {
windowManager.removeView(view)
}
}
}
}
doWithStartForegroundServiceAllowed { FtpServerService.toggle(this) }
}
}

0 comments on commit 7a2b228

Please sign in to comment.