@@ -4,6 +4,8 @@ import java.io.File
44import java.util.concurrent.TimeUnit
55
66object AdbInput {
7+
8+ // --- ADB Configuration ---
79 var selectedDevice: String? = null
810
911 private val adbExecutablePath: String by lazy {
@@ -22,51 +24,7 @@ object AdbInput {
2224 found?.absolutePath ? : error(" ADB not found in common locations. Please install Android SDK." )
2325 }
2426
25- private fun exec (command : String , waitAfter : Long = 100): Process {
26- val commandParts = mutableListOf<String >()
27- commandParts.add(adbExecutablePath) // Always start with the full path to adb
28-
29- selectedDevice?.let { deviceId ->
30- if (command != " devices" ) {
31- commandParts.add(" -s" )
32- commandParts.add(deviceId)
33- }
34- }
35-
36- // Add the the command parts
37- if (command.startsWith(" install " )) {
38- // Split the command into only two parts: "install" and the file path.
39- // The 'limit = 2' is crucial as it stops splitting after the first space.
40- val parts = command.split(" " , limit = 2 )
41- commandParts.addAll(parts)
42- } else {
43- // Keep the original logic for all other commands.
44- commandParts.addAll(command.split(" " ))
45- }
46-
47- println (" DEBUG: Executing command parts: $commandParts " )
48-
49- val processBuilder = ProcessBuilder (commandParts)
50-
51- val environment = processBuilder.environment()
52- val userHome = System .getProperty(" user.home" )
53- environment[" HOME" ] = userHome
54- environment[" ANDROID_SDK_HOME" ] = " $userHome /.android"
55-
56- val process = processBuilder.redirectErrorStream(true ).start()
57-
58- val finished = process.waitFor(5 , TimeUnit .SECONDS )
59- if (! finished) {
60- println (" DEBUG: Process timed out. Forcibly destroying." )
61- process.destroyForcibly()
62- }
63-
64- Thread .sleep(waitAfter)
65- return process
66- }
67-
68- // --- ADB Public Methods ---
69-
27+ // --- Device Management ---
7028 fun getDevices (): String {
7129 return try {
7230 val process = exec(" devices" )
@@ -90,7 +48,12 @@ object AdbInput {
9048 }
9149 }
9250
93- // power
51+ fun connectWireless (port : String ): String {
52+ val connect = exec(" connect $port " )
53+ return connect.inputStream.bufferedReader().readText()
54+ }
55+
56+ // --- Power & Boot Commands ---
9457 fun powerButton () = exec(" shell input keyevent 26" )
9558 fun longPressPowerButton () = exec(" shell input keyevent --longpress 26" )
9659 fun shutdownLegacy () = exec(" shell shutdown" )
@@ -101,7 +64,8 @@ object AdbInput {
10164
10265 fun isAwake (): Boolean {
10366 return try {
104- val output = exec(" shell dumpsys power | grep \" mWakefulness=\" " ).inputStream.bufferedReader().readText()
67+ val output = exec(" shell dumpsys power | grep \" mWakefulness=\" " )
68+ .inputStream.bufferedReader().readText()
10569 output.contains(" Awake" )
10670 } catch (e: Exception ) {
10771 println (" ERROR reading isAwake stream: ${e.message} " )
@@ -118,57 +82,117 @@ object AdbInput {
11882 println (" Screen is OFF. Sending wakeup command..." )
11983 exec(" shell input keyevent KEYCODE_WAKEUP" )
12084 Thread .sleep(500 )
121- unlock(password) // recursive calls, edit later to have attempts.
85+ unlock(password) // recursive call (can be improved later)
12286 }
12387 }
12488
89+ // --- Text Input ---
12590 fun sendText (message : String ) {
12691 val formatted = formatMessage(message)
12792 exec(" shell input text \" $formatted \" " )
12893 }
12994
13095 fun sendEnter () = exec(" shell input keyevent KEYCODE_ENTER" )
13196 fun sendKey (keyCode : Int ) = exec(" shell input keyevent $keyCode " )
132- fun logCat (): String {
133- val read = exec(" shell logcat" ).inputStream.bufferedReader().readText()
134- println (" logcat $read " )
135- return read
136- }
97+
98+ // --- Navigation / System UI ---
13799 fun homeButton () = exec(" shell am start -W -c android.intent.category.HOME -a android.intent.action.MAIN" )
138100 fun backButton () = exec(" shell input keyevent KEYCODE_BACK" )
139101 fun recentButton () = exec(" shell am start -n com.android.systemui/com.android.systemui.recents.RecentsActivity" )
140102 fun switchApp () = exec(" shell input keyevent KEYCODE_APP_SWITCH" )
103+
141104 fun nextButton () = exec(" shell input keyevent 22" )
142105 fun prevButton () = exec(" shell input keyevent 21" )
143106 fun upButton () = exec(" shell input keyevent 19" )
144107 fun downButton () = exec(" shell input keyevent 20" )
108+
145109 fun backspaceButton () = exec(" shell input keyevent 67" )
146110 fun tabButton () = exec(" shell input keyevent 61" )
147- fun selectAll () = exec(" shell input keycombination 113 29" )
148111 fun shiftTab () = exec(" shell input keycombination 59 61" )
112+ fun selectAll () = exec(" shell input keycombination 113 29" )
113+
149114 fun touchInput (x : Int , y : Int ) = exec(" shell input tap $x $y " )
115+
116+ fun holdInputTime (
117+ startX : Int ,
118+ startY : Int ,
119+ endX : Int? = startX,
120+ endY : Int? = startY,
121+ time : Int? = 500
122+ ) = exec(" shell input swipe $startX $startY $endX $endY $time " )
123+
124+ fun swipeUp () = holdInputTime(500 , 2000 , 500 , 500 , 100 )
125+ fun swipeDown () = holdInputTime(500 , 500 , 500 , 2000 , 100 )
126+
127+ // --- APK / App Management ---
128+ fun install (apk : String ): String {
129+ val install = exec(" install $apk " )
130+ return install.inputStream.bufferedReader().readText()
131+ }
132+
133+ fun openApp (packageName : String , activityName : String = ""): String {
134+ val cmd = if (activityName.isNotEmpty()) {
135+ " shell am start -n $packageName /.$activityName "
136+ } else {
137+ " shell am start $packageName "
138+ }
139+
140+ val open = exec(cmd)
141+ return open.inputStream.bufferedReader().readText()
142+ }
143+
150144 fun forceClose () {
151145 switchApp()
152146 holdInputTime(500 , 1000 , endY = 100 , time = 100 )
153147 }
154- fun swipeUp () = holdInputTime(500 , 2000 , 500 , 500 , 100 )
155- fun swipeDown () = holdInputTime(500 , 500 , 500 , 2000 , 100 )
156- fun holdInputTime (
157- startX : Int , startY : Int , endX : Int? = startX, endY : Int? = startY, time : Int? = 500
158- ) = exec(" shell input swipe $startX $startY $endX $endY $time " )
159148
160149 fun activityManager () = exec(" shell am start -a android.intent.action.VIEW" )
161150
162- // adb connect wifi adb
163- fun connectWireless (port : String ): String {
164- val connect = exec(" connect $port " )
165- return connect.inputStream.bufferedReader().readText()
151+ // --- Logcat ---
152+ fun logCat (): String {
153+ val read = exec(" shell logcat" ).inputStream.bufferedReader().readText()
154+ println (" logcat $read " )
155+ return read
166156 }
167157
168- // apk install
169- fun install (apk : String ): String {
170- val install = exec(" install $apk " )
171- return install.inputStream.bufferedReader().readText()
158+ // --- Private Helpers ---
159+ private fun exec (command : String , waitAfter : Long = 100): Process {
160+ val commandParts = mutableListOf<String >()
161+ commandParts.add(adbExecutablePath)
162+
163+ selectedDevice?.let { deviceId ->
164+ if (command != " devices" ) {
165+ commandParts.add(" -s" )
166+ commandParts.add(deviceId)
167+ }
168+ }
169+
170+ if (command.startsWith(" install " )) {
171+ val parts = command.split(" " , limit = 2 )
172+ commandParts.addAll(parts)
173+ } else {
174+ commandParts.addAll(command.split(" " ))
175+ }
176+
177+ println (" DEBUG: Executing command parts: $commandParts " )
178+
179+ val processBuilder = ProcessBuilder (commandParts)
180+
181+ val environment = processBuilder.environment()
182+ val userHome = System .getProperty(" user.home" )
183+ environment[" HOME" ] = userHome
184+ environment[" ANDROID_SDK_HOME" ] = " $userHome /.android"
185+
186+ val process = processBuilder.redirectErrorStream(true ).start()
187+ val finished = process.waitFor(5 , TimeUnit .SECONDS )
188+
189+ if (! finished) {
190+ println (" DEBUG: Process timed out. Forcibly destroying." )
191+ process.destroyForcibly()
192+ }
193+
194+ Thread .sleep(waitAfter)
195+ return process
172196 }
173197
174198 private fun formatMessage (input : String ): String {
0 commit comments