Before API level 11, it was possible to set the content of the clipboard by using the service program on the adb shell:
service call SERVICE CODE [i32 INT | s16 STR] ...
Options:
i32: Write the integer INT into the send parcel.
s16: Write the UTF-16 string STR into the send parcel.
There were three integer codes to define the methods:
1 TRANSACTION_getClipboardText
2 TRANSACTION_setClipboardText
3 TRANSACTION_hasClipboardText
For instance this command
$ adb shell service call clipboard 2 i32 1 i32 1 s16 "Hello Android!"
set the clipboard's content to "Hello Android!". As of API level 11 the listed methods are deprecated and the new ones take ClipData as an argument. How do you set the clipboard content now via adb shell?
You've asked two different questions here. The service calls are not related to the API functions.
Android is in general overly-aggressive about marking APIs as deprecated. In this case, it only means that there are new functions with more functionality. The functionality of getText(), hasText(), and setText() still exists and those functions will continue to work, but they are now implemented as trivial wrappers around the newer functions.
As far as the service calls go, those are an internal implementation detail and as you've noticed are not guaranteed to work across Android versions. If you peer into the Android source code, you'll find these transactions currently defined:
TRANSACTION_setPrimaryClip = 1
TRANSACTION_getPrimaryClip = 2
TRANSACTION_getPrimaryClipDescription = 3
TRANSACTION_hasPrimaryClip = 4
TRANSACTION_addPrimaryClipChangedListener = 5
TRANSACTION_removePrimaryClipChangedListener = 6
TRANSACTION_hasClipboardText = 7
The source code also indicates what parameters these transactions require. Unfortunately, TRANSACTION_setPrimaryClip requires a ClipData, which is not an i32 or an s16 and thus is not compatible with service call. We have bigger problems than that however; these transactions require the calling package name as a parameter, and the clipboard service validates that the specified package name matches the calling uid. When using the adb shell, the calling uid is either UID_ROOT or UID_SHELL, neither of which owns any packages, so there is no way to pass that check. Simply put, the new clipboard service cannot be used this way.
What can you do about all this? You can create your own service for manipulating the clipboard from the commandline and install it onto your device. I don't know if there's any way to extend service call, but you can use am startservice as a suitable replacement. If you've created and installed that custom clipboard service, then you could invoke it as:
am startservice -a MySetClipboard -e text "clipboard text"
The code to implement this service could look like this:
public MyService extends Service {
public int onStartCommand(Intent intent, int flags, int startId) {
String text = intent.getStringExtra("text");
ClipboardManager.setText(text);
stopSelf();
return START_NOT_STICKY;
}
}
The service should have an intent-filter that declares it capable of handling the MySetClipboard intent action.
I found a way to do this using com.tengu.sharetoclipboard. You install it with F-Droid, then you start it with am over adb with the following arguments:
adb shell am start-activity \
-a android.intent.action.SEND \
-e android.intent.extra.TEXT <sh-escaped-text> \
-t 'text/plain' \
com.tengu.sharetoclipboard
<sh-escaped-text> is the new contents of the android clipboard. Note that this text must be escaped so that it is not interpreted specially by sh on the remote end. In practice, that means surrounding it with single quotes and replacing all single quotes with '\''. For instance, this would work fine if the local shell is fish:
adb shell am start-activity \
-a android.intent.action.SEND \
-e android.intent.extra.TEXT '\'I\'\\\'\'m pretty sure $HOME is set.\'' \
-t 'text/plain' \
com.tengu.sharetoclipboard
After fish parses it, the argument is 'I'\''m pretty sure $HOME is set.'. After sh parses it, the argument is I'm pretty sure $HOME is set..
Here's a python script to simplify this process:
#!/usr/bin/env python
import sys
import os
def shsafe(s):
return "'" + s.replace("'", "'\\''") + "'"
def exec_adb(text):
os.execvp('adb', [
'adb', 'shell', 'am', 'start-activity',
'-a', 'android.intent.action.SEND',
'-e', 'android.intent.extra.TEXT', shsafe(text),
'-t', 'text/plain',
'com.tengu.sharetoclipboard',
])
if sys.stdin.isatty():
if len(sys.argv) >= 2:
exec_adb(' '.join(sys.argv[1:]))
else:
sys.stderr.write(
'''Send something to the android clipboard over ADB. Requires
com.tengu.sharetoclipboard.
acb <text>
<some command> | acb
acb <some_text_file.txt''')
exit(1)
else:
exec_adb(sys.stdin.read())
Related
I would like to get an adb command with a response of a code that map to current call state
the call state I mean are those in following link
https://developer.android.com/reference/android/telecom/Call.html#STATE_ACTIVE
those values are more representative and getting those values in command shell upon executing the adb command will be very helpful for me
I have only managed to get them on a log as per following command
adb logcat -d | findstr -i InCallFragment.setCallState
but I couldnot get the state value as a response of any adb command
Any help will be much appreciated
Thanks
for more illustration
please connect a phone to the PC , do a phone call and end it
use the above command to dump the buffer
refer to the state value
You can use adb shell service call telecom [code] command. The codes for getCallState() will be different depending on the Android version:
6.0.1: 26
7.0.0: 27
7.1.0: 27
7.1.2: 27
8.0.0: 29
8.1.0: 29
I have achieved what you want to do by modifying a custom ROM (LineageOS) and adding an android.util.Log line to print every state.
In my case I modified class:
Call
frameworks/opt/telephony/src/java/com/android/internal/telephony/Call.java
And what I did is inside getState(...) method, adding this line:
Log.i(myTAG, "getState state->" + mState.name());
With this what I have to do is search for myTAG in adb logcat.
I think otherwise you wont be able to do it...
You can dumpsys telecomm service:
adb shell dumpsys telecom
CallsManager:
mCalls:
[TC#7, ACTIVE, com.android.phone/com.android.services.telephony.TelephonyConnectionService, tel:***, A, childs(0), has_parent(false), [Capabilities: CAPABILITY_HOLD CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO], [Properties:]]
mCallAudioManager:
All calls:
TC#7
Active dialing, or connecting calls:
TC#7
Ringing calls:
Holding calls:
Foreground call:
[TC#7, ACTIVE, com.android.phone/com.android.services.telephony.TelephonyConnectionService, tel:***, A, childs(0), has_parent(false), [Capabilities: CAPABILITY_HOLD CAPABILITY_SUPPORT_HOLD CAPABILITY_MUTE CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO], [Properties:]]
mTtyManager:
mCurrentTtyMode: 0
mInCallController:
mInCallServices (InCalls registered):
.
.
Call TC#7 [2018-06-05 14:38:41.505](MO - outgoing)
To address: tel:***
14:38:41.508 - CREATED:PCR.oR#DMA
14:38:41.511 - SET_CONNECTING (ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}, [8c3d1caa626a79d75b154221ea94852a62fee7b3], UserHandle{0}):PCR.oR#DMA
14:38:41.847 - AUDIO_ROUTE (Leaving state QuiescentEarpieceRoute):PCR.oR->CAMSM.pM_2001->CARSM.pM_SWITCH_FOCUS#DMA_2_2
14:38:41.847 - AUDIO_ROUTE (Entering state ActiveEarpieceRoute):PCR.oR->CAMSM.pM_2001->CARSM.pM_SWITCH_FOCUS#DMA_2_2
14:38:43.442 - BIND_CS (ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}):NOCBIR.oR#DMU
14:38:43.519 - CS_BOUND (ComponentInfo{com.android.phone/com.android.services.telephony.TelephonyConnectionService}):SBC.oSC#DMY
14:38:43.519 - START_CONNECTION (tel:***):SBC.oSC#DMY
14:38:43.703 - CAPABILITY_CHANGE (Current: [[ sup_hld mut !v2a]], Removed [[]], Added [[ sup_hld mut !v2a]]):CSW.hCCC#DMg
14:38:43.706 - SET_DIALING (successful outgoing call):CSW.hCCC#DMg
14:38:47.560 - SET_ACTIVE (active set explicitly):CSW.sA#DNM
14:38:47.639 - CAPABILITY_CHANGE (Current: [[ hld sup_hld mut !v2a]], Removed [[]], Added [[ hld]]):CSW.sCC#DNY
Timings (average for this call, milliseconds):
bind_cs: 77.00
outgoing_time_to_dialing: 187.00
I want to run any app (say Settings) after rebooting tablet. Can I use os.system or do I have to use other methods.
import os,time
for i in range(0,3):
os.system("adb reboot")
time.sleep(60)
Yes, you can use os.system to execute ADB commands. If you want to validate the command executed successfully, take a look at the check_output(...) function which is apart of the subprocess library. This code snipet is how I choose to implement the check_output function. For the full code look here.
def _run_command(self, cmd):
"""
Execute an adb command via the subprocess module. If the process exits with
a exit status of zero, the output is encapsulated into a ADBCommandResult and
returned. Otherwise, an ADBExecutionError is thrown.
"""
try:
output = check_output(cmd, stderr=subprocess.STDOUT)
return ADBCommandResult(0,output)
except CalledProcessError as e:
raise ADBProcessError(e.cmd, e.returncode, e.output)
To launch an application you can use the command am start -n yourpackagename/.activityname. To launch the Settings App, run adb shell am start -n com.android.settings/com.android.settings.Settings. This stackoverflow question shows you in detail the options you can use to start the application via a command line intent.
Other tips:
I created an ADB wrapper written in python along with a few other python utilities that may aid in what you are trying to accomplish. For example, instead of calling time.sleep(60) to wait for the reboot, you use adb to poll the status of the property sys.boot_completed and once the property is set the device has finished booting and you can launch any application. Below is a reference implementation you can use.
def wait_boot_complete(self, encryption='off'):
"""
When data at rest encryption is turned on, there needs to be a waiting period
during boot up for the user to enter the DAR password. This function will wait
till the password has been entered and the phone has finished booting up.
OR
Wait for the BOOT_COMPLETED intent to be broadcast by check the system
property 'sys.boot_completed'. A ADBProcessError is thrown if there is an
error communicating with the device.
This method assumes the phone will eventually reach the boot completed state.
A check is needed to see if the output length is zero because the property
is not initialized with a 0 value. It is created once the intent is broadcast.
"""
if encryption is 'on':
decrypted = None
target = 'trigger_restart_framework'
print 'waiting for framework restart'
while decrypted is None:
status = self.adb.adb_shell(self.serial, "getprop vold.decrypt")
if status.output.strip() == 'trigger_restart_framework':
decrypted = 'true'
#Wait for boot to complete. The boot completed intent is broadcast before
#boot is actually completed when encryption is enabled. So 'key' off the
#animation.
status = self.adb.adb_shell(self.serial, "getprop init.svc.bootanim").output.strip()
print 'wait for animation to start'
while status == 'stopped':
status = self.adb.adb_shell(self.serial, "getprop init.svc.bootanim").output.strip()
status = self.adb.adb_shell(self.serial, "getprop init.svc.bootanim").output.strip()
print 'waiting for animation to finish'
while status == 'running':
status = self.adb.adb_shell(self.serial, "getprop init.svc.bootanim").output.strip()
else:
boot = False
while(not boot):
self.adb.adb_wait_for_device(self.serial)
res = self.adb.adb_shell(self.serial, "getprop sys.boot_completed")
if len(res.output.strip()) != 0 and int(res.output.strip()) is 1:
boot = True
I would like to start a background SL4A script (on a remote device) from within a different SL4A script. I can launch a script from a terminal by running something like this:
$ am start -a \
com.googlecode.android_scripting.action.LAUNCH_BACKGROUND_SCRIPT -n \
com.googlecode.android_scripting/.activity.ScriptingLayerServiceLauncher -e \
com.googlecode.android_scripting.extra.SCRIPT_PATH /sdcard/sl4a/scripts/main.py
I can't translate this into a startActivity call in Python.
The answer to a different question on opening a Twitter client works nicely, but I don't know how to extend that code. For example, how would you add a script path, and where would you put the line com.googlecode.android_scripting/.activity.ScriptingLayerServiceLauncher?
This function will launch any SL4A script from inside another one.
The first argument should be a path to the script you want to launch. The script can be in any language you have an interpreter installed for.
The second argument is optional and should be a bool. It defaults to False. It controls whether the terminal will be visible, so you can see output and errors. It does not effect whether the script has a UI or not.
from android import Android
droid = Android()
def launch_script(path, visible=False):
visibilty = 'FORE' if visible else 'BACK'
activity = 'com.googlecode.android_scripting.action.LAUNCH_{0}GROUND_SCRIPT'.format(visibilty)
extras = {'com.googlecode.android_scripting.extra.SCRIPT_PATH': path}
packagename = 'com.googlecode.android_scripting'
classname = 'com.googlecode.android_scripting.activity.ScriptingLayerServiceLauncher'
intent = droid.makeIntent(activity, None, None, extras, None, packagename, classname).result
droid.startActivityIntent(intent)
There's a gist for this code here.
After many, many failed attempts, I now have this working in Ruby - I had an easier time generating the JSON extras this way than in Python.
Important!
In the command-line version, you call on "com.googlecode.android_scripting/.activity.ScriptingLayerServiceLauncher"
From within a script, this is called as "com.googlecode.android_scripting.activity.ScriptingLayerServiceLauncher", without the slash. Leaving in the slash crashes sl4a.
[code]
require 'android'
require 'json/pure'
d=Android.new
script = '/sdcard/sl4a/scripts/YOUR_SCRIPT'
data = {"com.googlecode.android_scripting.extra.SCRIPT_PATH"=>script}
extras = JSON.generate(data)
d.startActivity('com.googlecode.android_scripting.action.LAUNCH_BACKGROUND_SCRIPT','','',data,true,'com.googlecode.android_scripting','com.googlecode.android_scripting.activity.ScriptingLayerServiceLauncher')
[/code]
I hope this helps!
Knowing the basic key mappings described in ADB Shell Input Events I get the emulation of text input and special keys working quite well. But what about Unicode characters? For instance I want to use umlauts from the German QWERTZ keyboard layout.
This gets me:
$ adb shell input text ö
Killed
So it seems to crash and
adb shell input text \xFC
prints xFC on the input. I have tried to the the events with getevent but I haven't found a direct mapping, I've also looked into the keymapping file /system/usr/keylayout/Qwerty.kl
I believe the only possibility is via the clipboard, but as pointed out in the question Pasting text into Android emulator clipboard using adb shell it seems to be unknown how to use it for Android Ice Cream Sandwich or later..
I wrote a virtual keyboard that accept broadcast intent, so you can send unicode characters to the editText view via adb.
for e.g.
adb shell am broadcast -a ADB_INPUT_TEXT --es msg "你好嗎! Hello!"
Here is the github project:
https://github.com/senzhk/ADBKeyBoard
Hope this little project would help.
Actually ADBKeyBoard is very good! Thanks for Eric Tang !
Some useful extensions for comfortable usage:
Switch to ADBKeyBoard from adb:
adb shell ime set com.android.adbkeyboard/.AdbIME
Check your available le virtual keyboards:
ime list -a
Use simple quote characters -not double as in example above- if your shell not accepts "!" (explanation sign)
adb shell am broadcast -a ADB_INPUT_TEXT --es msg 'Accented characters here'
Switch back to original virtual keyboard: (swype in my case...)
adb shell ime set com.nuance.swype.dtc/com.nuance.swype.input.IME
Use adb over wifi to simplify your life... :)
input won't work because it can only send single key event through the virtual keyboard (check the source code if you don't know what I mean).
I think the only way left is using Instrumentation. I guess you can create a test for your Activity and then do something like this:
final Instrumentation instrumentation = getInstrumentation();
final long downTime = SystemClock.uptimeMillis();
final long eventTime = SystemClock.uptimeMillis();
final KeyEvent altDown = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_DOWN,
KeyEvent.KEYCODE_GRAVE, 1, KeyEvent.META_ALT_LEFT_ON);
final KeyEvent altUp = new KeyEvent(downTime, eventTime, KeyEvent.ACTION_UP,
KeyEvent.KEYCODE_GRAVE, 1, KeyEvent.META_ALT_LEFT_ON);
instrumentation.sendKeySync(altDown);
instrumentation.sendCharacterSync(KeyEvent.KEYCODE_A);
instrumentation.sendKeySync(altUp);
instrumentation.sendKeySync(altDown);
instrumentation.sendCharacterSync(KeyEvent.KEYCODE_E);
instrumentation.sendKeySync(altUp);
instrumentation.sendKeySync(altDown);
instrumentation.sendCharacterSync(KeyEvent.KEYCODE_I);
instrumentation.sendKeySync(altUp);
instrumentation.sendKeySync(altDown);
instrumentation.sendCharacterSync(KeyEvent.KEYCODE_O);
instrumentation.sendKeySync(altUp);
instrumentation.sendKeySync(altDown);
instrumentation.sendCharacterSync(KeyEvent.KEYCODE_U);
instrumentation.sendKeySync(altUp);
This will send the modified keys: àèìòù
update 2022
https://stackoverflow.com/a/71367206/236465 shows another solution using AndroidViewClient/culebra and CulebraTester2-public backend.
I need to paste text into the Android emulator clipboard using adb shell.
tried on Android 1.6 and 2.3.1
I tried to use adb shell command: clipboard:[android.text.iclipboard]
"service call clipboard" where service codes are 1, 2, and 3, for getClipboardText, setClipboardText, and hasClipboardText respectively.
service call clipboard 2 s16 thisisinsertedtext
does not seem to work
while
service call clipboard 1
shows the content of clipboard:
service call clipboard 1
Result: Parcel(
0x00000000: 00000000 00000001 00000001 00000004 '................'
0x00000010: 00650074 00740078 00000000 't.e.x.t..... ')
Please advise how to set a value for emulator clipboard!
Use below command.
service call clipboard 2 i32 1 i32 18 s16 thisisinsertedtext
I think that the first one, "i32 1" is how many elements in clipboard. So, just one.
Second is a length of string.
The command written above shows...
Result: Parcel(00000000 '....')
This usually means OK, no error.
So, my question is, is there any way to copy unicode string?
I mean, muti-byte character sets, like Korean.
I tried many way, but it failed.
Looks like all 3 old methods are deprecated since API Level 11 so it won’t work for ICS
Not clear if it's even possible to make it work with service call clipboard anymore...
static final int TRANSACTION_getClipboardText 1
static final int TRANSACTION_hasClipboardText 3
static final int TRANSACTION_setClipboardText 2
www.androidjavadoc.com/1.0_r1_src/constant-values.html
http://developer.android.com/reference/android/content/ClipboardManager.html
http://developer.android.com/guide/topics/text/copy-paste.html
adb shell service call clipboard 2 i32 1 i32 1 s16 "你好吗"
Result: Parcel(00000000 '....')
That is OK.
"你好吗" is Chinese character.
The second 'i32 1' can be any integer, maybe...
Try this:
i32: Write the integer INT into the send parcel.
s16: Write the UTF-16 string STR into the send parcel.
Using adb shell command directly do not work since API Level 11.
Here is a solution.
There is an open source python script that can deal with the severe limitations: https://github.com/gcb/AdbPaste - and it works well enough except for long clipboard file uploads it's incredibly slow (200 line text file can take 20 minutes).
I found some code on GitHub for an app called clipper that can use adb to populate clipboard via a broadcast intent. I enhanced it to read from a file, the enhanced code is here: https://github.com/RoundSparrow/clipper
Build the app, install on the device. Now I can use ADB commands to populate the clipboard via a file. Works like a charm for a 3 page script I need to upload. Essentially you use like this:
adb push clipboard_content_file.txt /sdcard/clipboard_content_file.txt
adb shell am broadcast -a clipper.setfile -e filepath \'/sdcard/clipboard_content_file.txt\'
It's much faster AdbPaste, it takes only a second or two regardless of the size of the clipboard content.