java - 除了 TimerTask 之外,还有其他方法可以在另一个应用程序上显示覆盖吗?
问题描述
我正在构建一个应用程序,该应用程序显示覆盖另一个应用程序,例如应用程序储物柜。但它不喜欢它。每次打开应用程序时,我都想在数据库中存在的应用程序上显示一个对话框。我提供了一项服务,该服务使用设置为延迟和 1 秒周期的计时器任务连续检查哪个应用程序处于前台。
问题在于,由于计时器任务运行函数中的一条语句,它在每个应用程序上只显示一次对话框。我怎样才能使它工作,以便它始终在应用程序上显示对话框。任何替代或优化?
import android.app.ActivityManager
import android.app.Dialog
import android.app.Service
import android.app.usage.UsageStats
import android.app.usage.UsageStatsManager
import android.content.Context
import android.content.Intent
import android.graphics.PixelFormat
import android.os.Build
import android.os.IBinder
import android.util.Log
import android.view.Gravity
import android.view.View
import android.view.WindowManager
import android.widget.ImageView
import androidx.annotation.RequiresApi
import app.privvio.android.policysplash.PolicyDialog
import app.privvio.android.preference.GetFirebaseAllApps
import java.util.*
import kotlin.collections.ArrayList
class AppCheckServices : Service() {
private var context: Context? = null
var imageView: ImageView? = null
private var windowManager: WindowManager? = null
private var dialog: Dialog? = null
var dbPackageName: ArrayList<String> = GetFirebaseAllApps().getAppsUploaded()
override fun onCreate() {
super.onCreate()
context = applicationContext
/** Timer started for long time **/
timer = Timer("AppCheckServices")
timer!!.scheduleAtFixedRate(updateTask, 1000L, 1000L)
/** Window Manager posts a Blank Image
* view with transparent background which blocks the view
* and the policy dialog is shown over it
* **/
windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
imageView = ImageView(this)
imageView!!.visibility = View.GONE
val LAYOUT_FLAG: Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} else {
WindowManager.LayoutParams.TYPE_PHONE
}
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
LAYOUT_FLAG,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSPARENT)
params.gravity = Gravity.TOP or Gravity.CENTER
params.x = applicationContext.resources.displayMetrics.widthPixels / 2
params.y = applicationContext.resources.displayMetrics.heightPixels / 2
windowManager!!.addView(imageView, params)
}
private val updateTask: TimerTask = object : TimerTask() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
override fun run() {
currentApp = ForegroundApps
if (dbPackageName.contains(ForegroundApps)) {
Log.d("DBAppFRGRND", "true : The application is in foreground.")
if (imageView != null) {
imageView!!.post {
if (currentApp != previousApp) {
showPolicyDialog()
previousApp = currentApp
} else {
Log.d("AppCheckService", "currentApp matches previous App")
}
}
}
} else {
Log.d("DBAppFRGRND", "false : The application is not uploaded to the server. ")
if (imageView != null) {
imageView!!.post {
hidePolicyDialog();
}
}
}
}
}
/** This section tells whether an application is in foreground or background */
val ForegroundApps: String?
@RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
get() {
var mpackageName: String? = null
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
val usm = this.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val time = System.currentTimeMillis()
val appList: List<UsageStats>? = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, 0, time)
if (appList != null && appList.isNotEmpty()) {
val sortedMap = TreeMap<Long, UsageStats>()
for (usageStats in appList) {
sortedMap[usageStats.lastTimeUsed] = usageStats
}
mpackageName = sortedMap.takeIf { it.isNotEmpty() }?.lastEntry()?.value?.packageName
Log.d(TAG, "isEmpty No : $mpackageName")
} else {
Log.d(TAG, "isEmpty Yes")
mpackageName = ""
}
} else {
val am = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
@Suppress("DEPRECATION") //The deprecated method is used for devices running an API lower than LOLLIPOP
mpackageName = am.getRunningTasks(5)[0].topActivity?.packageName
Log.d(TAG, "isEmpty No : $mpackageName")
}
return mpackageName
}
fun showPolicyDialog() {
if (context == null) context = applicationContext
PolicyDialog(context!!).showDialog(context!!)
}
fun hidePolicyDialog() {
previousApp = ""
try {
if (dialog != null) {
if (dialog!!.isShowing) {
dialog!!.dismiss()
}
}
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
}
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
/** We want this service to continue running until it is explicitly
* stopped, so return sticky.
*/
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
// timer!!.cancel()
// timer = null
if (imageView != null) {
windowManager!!.removeView(imageView)
}
try {
if (dialog != null) {
if (dialog!!.isShowing) {
dialog!!.dismiss()
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
companion object {
const val TAG = "AppCheckServices"
var currentApp: String? = ""
var previousApp: String? = ""
var timer: Timer? = null
}
}
解决方案
推荐阅读
- javascript - 反应原生不会导入另一个组件
- jmeter - 如何从jmeter中的请求中提取值
- python - 在 for 循环中迭代 fetchall() 字典不起作用
- android - Android Studio:在画布上绘制位图问题
- python - 尽管可能有结局,但广度的算法永远运行
- r - 将图例移出情节区域(素食套餐)
- python - Errno 2 从子文件夹导入 python 脚本时没有此类文件或目录错误
- python - 如何接受 GET 请求并将其转换为 JSON 对象?
- excel - 复制和粘贴行但不覆盖隐藏的行
- pytorch - 如何在 PyTorch Lightning 中编写多个训练设置