Search code examples
androidkotlinadb

retrieve text to Linux terminal for Android service run with adb


I would like an Android service (written in Kotlin) run in a Linux terminal to print out a message in the terminal it's running in. The main Kotlin class is in this file (I cloned that repo).

I'll want to modify that in various ways, but for now I just want to see if it's possible to print to the terminal. So I have tried adding statements like

print("message")
println("message")
Log.d(TAG, "message")
Log.i(TAG, "message")

etc. (see also this other SO question which suggested these, seemingly for a somewhat different purpose).

My problem:

While "message" does appear in the Android logs (viewed with adb logcat), and the message types match the type of logging I asked for (e.g. for Log.i it appears in the log as I <service-name>: message), I would nevertheless like to see it directly in the terminal where I have run the adb command that starts the service.

Is this possible?


Solution

  • I never did find out how to do this by calling an Android service via adb, so I resorted to a broadcast receiver instead.

    My manifest file now registers the receiver:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.grobber.cliprecv">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <activity android:name=".InfoScreenActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
            <receiver android:name=".MyBroadcastReceiver"  android:exported="true" android:enabled="true">
              <intent-filter>            
                <action android:name="get" />
                <action android:name="set" />
              </intent-filter>
            </receiver>
        </application>
    </manifest>
    

    (note that there's now no service at all for the app). In turn, the receiver class is defined in a Kotlin file as follows:

    private const val TAG = "MyBroadcastReceiver"
    
    class MyBroadcastReceiver :
        BroadcastReceiver() {    
                                 override fun onReceive(context: Context, intent: Intent) {
                                     val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                                     if (intent.getAction().equals("get")) {
                                         val res: String
                                         if (clipboard.hasPrimaryClip()) {
                                             val cliptext = clipboard.getPrimaryClip()?.getItemAt(0)?.coerceToText(context)?: ""
                                             res=cliptext.toString()
                                         } else {
                                             res = ""
                                         }          
                                         setResultData(res)
                                     } else if (intent.getAction().equals("set")) {
                                         val str: String? = intent.getStringExtra("text")
                                         clipboard.primaryClip = ClipData.newPlainText(TAG, str)    
                                     }                               
                                 }
        }
    

    Now, with the Android device connected to a computer and the app running in the foreground, running

     adb shell am broadcast -n com.grobber.cliprecv/.MyBroadcastReceiver -a get
    

    will give me back the contents of the clipboard in my terminal as the data section of the output:

    $ adb shell am broadcast -n com.grobber.cliprecv/.MyBroadcastReceiver -a get
    ---
    Broadcasting: Intent { act=get flg=0x400000 cmp=com.grobber.cliprecv/.MyBroadcastReceiver }
    Broadcast completed: result=0, data="<CLIPBOARD CONTENTS>"
    

    Reference

    The solution was adapted from this older app that similarly uses a broadcast receiver to get/set the clipboard.