Skip to content
Prev Previous commit
Next Next commit
update
  • Loading branch information
AAswordman committed Dec 12, 2025
commit 9871338d9554658022f10a74fca184d92ac18733
7 changes: 7 additions & 0 deletions README(E).md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ Rich MCP ecosystem

---

## 🔮 Roadmap / TODO

- **UI automation & screenshot pipeline**
- ⏳ Exploring deeper UI automation powered by Shizuku/Root (e.g., more robust pipelines, virtual-display-like flows)

---

## 📅 Version History

<table>
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ AI自动分类管理记忆,智能搜索历史对话,记住您的偏好和习

---

## 🔮 TODO / 开发计划

- **UI 自动化与截图管线**
- ⏳ 基于 Shizuku/Root 的更强 UI 自动化能力调研中(例如更稳定的截图管线、虚拟屏等方向)

---

## 📅 版本更新历程

<table>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.ai.assistance.operit.core.tools.defaultTool.standard

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import com.ai.assistance.operit.api.chat.EnhancedAIService
import com.ai.assistance.operit.core.config.FunctionalPrompts
import com.ai.assistance.operit.core.tools.AutomationExecutionResult
Expand All @@ -25,6 +27,7 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.delay
import java.io.File
import java.io.FileOutputStream
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
Expand Down Expand Up @@ -526,7 +529,7 @@ open class StandardUITools(protected val context: Context) {
}

val timestampFormat = SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.getDefault())
val fileName = "ui_screenshot_${timestampFormat.format(Date())}.png"
val fileName = "ui_screenshot_${timestampFormat.format(Date())}.jpg"
val file = File(screenshotDir, fileName)

val floatingService = FloatingChatService.getInstance()
Expand All @@ -540,6 +543,36 @@ open class StandardUITools(protected val context: Context) {
return null
}

try {
val originalBitmap = BitmapFactory.decodeFile(file.absolutePath)
if (originalBitmap != null) {
val width = originalBitmap.width
val height = originalBitmap.height
val maxDimension = 1080
val maxOriginalDim = if (width > height) width else height
val scale = maxOriginalDim.toFloat() / maxDimension.toFloat()

val targetBitmap = if (scale > 1f) {
val newWidth = (width / scale).toInt().coerceAtLeast(1)
val newHeight = (height / scale).toInt().coerceAtLeast(1)
Bitmap.createScaledBitmap(originalBitmap, newWidth, newHeight, true)
} else {
originalBitmap
}

FileOutputStream(file).use { out ->
targetBitmap.compress(Bitmap.CompressFormat.JPEG, 80, out)
}

if (targetBitmap !== originalBitmap) {
originalBitmap.recycle()
}
targetBitmap.recycle()
}
} catch (e: Exception) {
AppLogger.e(TAG, "captureScreenshotForAgent: downscale/compress failed: ${file.absolutePath}", e)
}

val imageId = ImagePoolManager.addImage(file.absolutePath)
if (imageId == "error") {
AppLogger.e(TAG, "captureScreenshotForAgent: failed to register image: ${file.absolutePath}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ class UIOperationOverlay private constructor(private val context: Context) {

// 自动清理延迟(毫秒)
private val AUTO_CLEANUP_DELAY_MS = 500L

// 隐藏悬浮窗前的额外展示时间(毫秒),用于让动画有机会完整显示
private val HIDE_DELAY_MS = 600L

// 操作类型
sealed class OperationType {
Expand Down Expand Up @@ -301,38 +304,40 @@ class UIOperationOverlay private constructor(private val context: Context) {
}

/**
* 隐藏所有反馈悬浮窗
* 隐藏所有反馈悬浮窗(延迟一点时间,让动画有机会显示)
*/
fun hide() {
runOnMainThread {
try {
// 清除所有待处理的移除任务
handler.removeCallbacksAndMessages(null)
// 清空所有事件列表
tapEvents.clear()
swipeEvents.clear()
textInputEvents.clear()
handler.postDelayed({
try {
// 清除所有待处理的移除任务
handler.removeCallbacksAndMessages(null)
// 清空所有事件列表
tapEvents.clear()
swipeEvents.clear()
textInputEvents.clear()

// 彻底移除视图
if (overlayView != null) {
lifecycleOwner?.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
lifecycleOwner?.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
lifecycleOwner?.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)

// 彻底移除视图
if (overlayView != null) {
lifecycleOwner?.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE)
lifecycleOwner?.handleLifecycleEvent(Lifecycle.Event.ON_STOP)
lifecycleOwner?.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
try {
windowManager?.removeView(overlayView)
} catch (e: Exception) {
AppLogger.e(TAG, "Error removing overlay view", e)
try {
windowManager?.removeView(overlayView)
} catch (e: Exception) {
AppLogger.e(TAG, "Error removing overlay view", e)
}

overlayView = null
lifecycleOwner = null
windowManager = null
AppLogger.d(TAG, "Overlay view dismissed")
}

overlayView = null
lifecycleOwner = null
windowManager = null
AppLogger.d(TAG, "Overlay view dismissed")
} catch (e: Exception) {
AppLogger.e(TAG, "Error dismissing overlay view", e)
}
} catch (e: Exception) {
AppLogger.e(TAG, "Error dismissing overlay view", e)
}
}, HIDE_DELAY_MS)
}
}
}
Expand Down