Starting share activity from ADB shell - android

I'm starting a sharing activity from ADB shell.
Specifically I am trying to achieve the same as this (working) java-snippet:
File dir = Environment.getExternalStorageDirectory();
File yourFile = new File(dir, "/_tmp/1.jpg");
Uri yourFileUri = Uri.fromFile(yourFile);
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sendIntent.setType("image/*");
sendIntent.putExtra(Intent.EXTRA_STREAM, yourFileUri);
sendIntent.setPackage("com.snapchat.android");
startActivity(sendIntent);
Here is the commands I am using:
adb shell am start -a android.intent.action.SEND -t image/jpeg --es android.intent.extra.STREAM file:///storage/emulated/0/_tmp/1.jpg com.snapchat.android --grant-read-uri-permission
The issue I am currently facing is that the snapchat app will open and load, flash black for a second but fails to load the image.
I have checked that the path to the image is working by issuing the following commands, and opening the image in the android gallery:
adb shell am start -t image/jpeg -d file:///storage/emulated/0/_tmp/1.jpg
What am I doing wrong?
Edit:
Using the command:
adb shell am start -a android.intent.action.SEND -t image/jpeg --es android.intent.extra.STREAM file:///storage/emulated/0/_tmp/1.jpg com.snapchat.android/com.snapchat.android.LandingPageActivity --grant-read-uri-permission
Gives the same result, however I compared it to the actual call in DDMS, see the difference here:
Log by sharing manually through the phone:
10-19 18:01:54.020: D/HtcShareActivity(21561): onItemClick: position=0 activity=com.snapchat.android/com.snapchat.android.LandingPageActivity
10-19 18:01:54.061: I/ActivityManager(724): START u0 {act=android.intent.action.SEND typ=image/jpeg flg=0x1 cmp=com.snapchat.android/.LandingPageActivity (has clip) (has extras)} from uid 10078 on display 0
Log by using the ADB command:
10-19 18:04:29.096: I/ActivityManager(724): START u0 {act=android.intent.action.SEND typ=image/jpeg flg=0x10000000 cmp=com.snapchat.android/.LandingPageActivity (has extras)} from uid 2000 on display 0
As you can see the (has clip) is not present in the ADB call.
Could it be that --grant-read-uri-permission isn't "working" or at least not giving sufficient permission?
How do I test and ultimately solve this?

You're opening your application with the intent, but, you're not declaring which Activity should handle the intent, which is why you see a flicker and then close - an Activity needs to handle the intent.
You need to declare in your command whats the MainActivity that is supposed to be handling the intent.
For example :
adb shell am start -a android.intent.action.SEND -t image/* --es
android.intent.extra.STREAM file:///storage/emulated/0/_tmp/1.jpg
com.snapchat.android/FULL_PATH_OF_YOUR_ACTIVITY
where FULL_PATH_OF_YOUR_ACTIVITY should be the activity declared as main activity in your manifest.
adb shell am start -a android.intent.action.SEND -t image/* --es
android.intent.extra.STREAM file:///storage/emulated/0/_tmp/1.jpg
com.snapchat.android/com.snapchat.android.sub.MainActivity
Sample manifest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.snapchat.android">
<application
android:theme="#style/AppTheme">
<activity android:name="com.snapchat.android.sub.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

It turned out I wasn't sending any real image data, I was simply sending a string by using --es, however the a URI was needed, and therefore I should have used --eu.
Updating the following command:
adb shell am start -a android.intent.action.SEND -t image/jpeg --es android.intent.extra.STREAM file:///storage/emulated/0/_tmp/1.jpg com.snapchat.android/com.snapchat.android.LandingPageActivity --grant-read-uri-permission
To:
adb shell am start -a android.intent.action.SEND -t image/jpeg --eu android.intent.extra.STREAM file:///storage/emulated/0/_tmp/1.jpg com.snapchat.android/com.snapchat.android.LandingPageActivity --grant-read-uri-permission
Solved my issue.
It was not due to leaving out declaration of the main activity that #Dus suggested. (Good thought though.)
The command can be simplified all the way down to:
adb shell am start -a android.intent.action.SEND -t image/jpeg --eu android.intent.extra.STREAM file:///storage/emulated/0/_tmp/1.jpg com.snapchat.android

Related

ADB cannot open account settings that list and allows to add accounts

I'm trying to use ADB to open one of the device settings. The setting screen that I want is the one that lists and allows us to add accounts to the device.
For example, adb shell am start -a android.settings.ADD_ACCOUNT_SETTINGS shows the accounts I can add.
I've managed to find that android shows the fragment com.android.settings.accounts.AccountDashboardFragment so tried to:
adb shell am start -n com.android.settings/com.android.settings.SubSettings -e :android:show_fragment com.android.settings.accounts.AccountDashboardFragment
but that throws:
adb shell am start -n com.android.settings/com.android.settings.SubSettings -e :android:show_fragment com.android.settings.accounts.AccountDashboardFragment
Starting: Intent { cmp=com.android.settings/.SubSettings (has extras) }
Exception occurred while executing 'start':
java.lang.SecurityException: Permission Denial: starting Intent { flg=0x10000000 cmp=com.android.settings/.SubSettings (has extras) } from null (pid=24379, uid=2000) not exported from uid 1000
at com.android.server.wm.ActivityStackSupervisor.checkStartAnyActivityPermission(ActivityStackSupervisor.java:1043)
at com.android.server.wm.ActivityStarter.executeRequest(ActivityStarter.java:999)
at com.android.server.wm.ActivityStarter.execute(ActivityStarter.java:669)
at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1096)
at com.android.server.wm.ActivityTaskManagerService.startActivityAsUser(ActivityTaskManagerService.java:1068)
at com.android.server.am.ActivityManagerService.startActivityAsUserWithFeature(ActivityManagerService.java:3662)
at com.android.server.am.ActivityManagerShellCommand.runStartActivity(ActivityManagerShellCommand.java:544)
at com.android.server.am.ActivityManagerShellCommand.onCommand(ActivityManagerShellCommand.java:186)
at android.os.BasicShellCommandHandler.exec(BasicShellCommandHandler.java:98)
at android.os.ShellCommand.exec(ShellCommand.java:44)
at com.android.server.am.ActivityManagerService.onShellCommand(ActivityManagerService.java:10505)
at android.os.Binder.shellCommand(Binder.java:929)
at android.os.Binder.onTransact(Binder.java:813)
at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:5053)
at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2867)
at android.os.Binder.execTransactInternal(Binder.java:1159)
at android.os.Binder.execTransact(Binder.java:1123)
Any idea how to bypass this?

ADB command line start activity permissions

I'm trying to trigger an activity using an intent using adb on the command line:
adb shell am start
-a android.intent.action.VIEW
-c android.intent.category.DEFAULT
-t vnd.google.android.package/vnd.google.android.package_something
-n com.google.android.package/com.google.android.apps.package.SomeActivity
but it throws a security exception:
Starting: Intent { act=android.intent.action.VIEW cat=[android.intent.category.DEFAULT] typ=vnd.google.android.package/vnd.google.android.package_something cmp=com.google.android.package/com.google.android.apps.package.SomeActivity }
java.lang.SecurityException: Permission Denial: starting Intent { act=android.intent.action.VIEW cat=[android.intent.category.DEFAULT] typ=vnd.google.android.package/vnd.google.android.package_something flg=0x10000000 cmp=com.google.android.package/com.google.android.apps.package.SomeActivity } from null (pid=31536, uid=2000) requires com.google.android.package.START_ACTIVITY
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at android.app.ActivityManagerProxy.startActivityAsUser(ActivityManagerNative.java:2767)
at com.android.commands.am.Am.runStart(Am.java:885)
at com.android.commands.am.Am.onRun(Am.java:361)
at com.android.internal.os.BaseCommand.run(BaseCommand.java:47)
at com.android.commands.am.Am.main(Am.java:101)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:251)
So I tried again with a user who has the missing permission:
adb shell am start
-a android.intent.action.VIEW -c android.intent.category.DEFAULT
-t vnd.google.android.package/vnd.google.android.package_something
-n com.google.android.package/com.google.android.apps.package.SomeActivity
--user 10088
but then it says that the activity doesn't exist:
Starting: Intent { act=android.intent.action.VIEW cat= [android.intent.category.DEFAULT] typ=vnd.google.android.package/vnd.google.android.package_something cmp=com.google.android.package/com.google.android.apps.package.SomeActivity }
Error type 3
Error: Activity class {com.google.android.package/com.google.android.apps.package.SomeActivity} does not exist.
Am I using the user parameter incorrectly? Do I need to include any more information?
You should start activities using the syntax below:
adb shell am start
-n com.google.android.package/.SomeActivity
In your case with user permission:
adb shell am start
-n com.google.android.package/.SomeActivity
--user 10088

How to start this activity use adb shell am start -D -d pg/xx.The activity name is Main$Activity

I want to debug android's so file. I use start an Activity: am start [-D] [-W] to start activitey.
the applicationg package name is com.dualboot.apps.springzen . the main activity is com.dualboot.apps.springzen.Main$Activity . i use command
'adb shell am start com.dualboot.apps.springzen/com.dualboot.springzen.Main$Actinity'
it's not exist
Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.dualboot.apps.springzen/com.dualboot.springzen.Main }
Error type 3
Error: Activity class {com.dualboot.apps.springzen/com.dualboot.springzen.Main} does not exist.
how to start this activity
Since you are calling a component you need to include the component -n option tag.
Use this:
adb shell am start -n com.dualboot.apps.springzen/.MainActivity
if you actually have the $ in your class name (I doubt it) which usually refers to an inner class then you need to use:
adb shell am start -n com.dualboot.apps.springzen/.Main\$Activity

am start cannot find main activity listed in manifest

I am trying to start an activity for an app (which I did not write in case you were wondering) through the adb shell. The manifest has the lines:
<activity android:label="#string/app_name" android:name="MainActivity$mainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I have tried using the the commands
adb shell am start -W com.pkg.name/MainActivity$mainActivity
adb shell am start -W com.pkg.name/.MainActivity$mainActivity
adb shell am start -W com.pkg.name/.MainActivity
adb shell am start -a android.intent.action.MAIN -n com.pkg.name/MainActivity$mainActivity
adb shell am start -n com.pkg.name/MainActivity$mainActivity
etc...
and each and every one gives me the error:
Error type 3
Error: Activity class {com.pkg.name/com.pkg.name.MainActivity}
does not exist.
It does however work when clicking on the app icon in the emulator, and by grepping the logcat output I find that the activity being launched is called .MainActivity$mainActivit or .MainActivity, they both show up in the output. Can someone tell me why am start is not working and how to in fact start this activity without manually clicking the icon?
UPDATE: The solution given by laalto is almost right. It turns out it was a problem with the $ getting resolved as an environment variable, however the command he suggested doesn't quite do it. You need to put single quotes around to <pkgname/activityname> in addition to escaping the $.
In unix-like shells, $ is a shell metacharacter so the $mainActivity expands to whatever value the environment variable mainActivity holds, likely an empty value in your case.
To escape it, use a backslash:
adb shell am start -W com.pkg.name/.MainActivity\$mainActivity
However, having an inner class as an entry point is sort of a code smell. Consider making the outer class your entry point. Then you wouldn't need $ in any form.
am start -n com.pkg.name/com.package.name.MainActivity$mainActivity
Good luck

Refresh Android mediastore using adb

I'm using adb to sync music on an android phone. Essentially, I rm the existing music directory and push replacement music files.
I'd like to be able to use adb to force a rescan, so that the google music player (and other apps) works properly with the new songs and playlists.
According to How can I refresh MediaStore on Android? you can force a rescan by broadcasting an appropriate intent.
adb provides 'shell am broadcast', which would seem to allow me to force a rescan from adb.
Alternatively I could run a rescan app or reboot, but I'd like to trigger the rescan from adb
What adb command should I issue? The music files and playlists are all in /sdcard/music.
The rescan apps use a media mount intent to kick off the media scanner. You can use am broadcast to send the same intent.
The command is:
adb shell am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///sdcard
The MEDIA_MOUNTED intent is no longer permitted (post KitKat) for non-system apps; try this instead.
It’s not recursive, though, and has to be run on the exact_file_name, so it’s not a good replacement.
adb shell am broadcast \
-a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
-d file:///mnt/sdcard/Music/<exact_file_name>
If you need to rescan recursively, you can use this command (fix paths accordingly):
adb shell "find /mnt/sdcard/Music/ -exec am broadcast \
-a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
-d file://{} \\;"
Or like this (if above won't work for you):
adb shell "find /mnt/sdcard/Music/ | while read f; do \
am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE \
-d \"file://${f}\"; done"
On some Samsung mobiles, you can get a full rescan like this:
am broadcast -a com.samsung.intent.action.MTP_FILE_SCAN -n com.android.providers.media/.MediaScannerReceiver
If you have rooted your phone, you can use this script I’ve written, which has the advantage of keeping track of which files have already been updated:
#!/system/bin/env busybox ash
MUSIC_LIBRARY=/sdcard/MusicLibrary
LAST_UPDATE="$(stat -c %Y "$MUSIC_LIBRARY/.last-update")"
find "$MUSIC_LIBRARY" -type f ! -iname ".last-update" | (
while read f; do
if ! test "$LAST_UPDATE" -ge "$(stat -c %Y "$f")"; then
am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d "file://$f"
touch "$f"
else
echo "Not updated: \`$f'"
fi
done
)
touch "$MUSIC_LIBRARY/.last-update"
Here's a Python script called adb-scan.
It uses adb to ask the Android device to rescan the given files.
Example usage:
$ adb-scan Notifications/\*.mp3
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/cough.mp3 flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/harmonica3.mp3 flg=0x400000 }
Broadcast completed: result=0
Broadcasting: Intent { act=android.intent.action.MEDIA_SCANNER_SCAN_FILE dat=file:///sdcard/Notifications/shhh.mp3 flg=0x400000 }
Broadcast completed: result=0
$
Here's the script:
#!/usr/bin/python3
#
# Ask the Android media scanner to check the given files.
#
import sys
import os
import re
sys.argv.pop(0)
if not sys.argv:
sys.exit('usage: adb-scan files...')
intent = 'android.intent.action.MEDIA_SCANNER_SCAN_FILE'
# Quote certain special characters such as spaces, backslashes and quotes. In
# particular, don't quote '*' because we want that to be expanded on the
# Android device.
def cleanup(arg):
if not arg.startswith('/'):
arg = '/sdcard/' + arg
arg = re.sub("[ \\'\"]", lambda x: '\\' + x.group(0), arg)
return arg
script = '''
for i in {args}; do
[ -e "$i" ] || echo "warning: no such file: $i"
am broadcast -a "{intent}" -d "file://$i"
done
'''.format(args=' '.join(map(cleanup, sys.argv)),
intent=intent)
cmd = ['adb', 'shell', script]
os.execvp(cmd[0], cmd)

Categories

Resources