Is there a way to auto answer whatsapp video call using AccessibilityService in Android?
OR is there a way to stimulate a click on headset's/bluetooth's call answering button? How can i get the id of the answering button?? to perform a click with accessibility service
I know that starting from Android 8.0 Oreo we have ANSWER_PHONE_CALLS permission, but for my project i want to use an old device for remote monitoring.
Any help would be appreciated!
----- Update: Thanks to the answer of Mr. hemisphire and Mr. Kahbazi, the app is able to answer the call,but needs to be a system app to work! is there any way to make it work without being a system app? without the headset's button hack?
public class AnswerCall extends AccessibilityService {
#Override
public void onAccessibilityEvent( AccessibilityEvent event )
{
if(event.getEventType() == TYPE_WINDOW_CONTENT_CHANGED)
{
if(event.getPackageName().equals("com.whatsapp"))
{
Thread thread = new Thread() {
#Override
public void run() {
try {
while(true) {
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_HEADSETHOOK);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
StringBuilder sb = new StringBuilder();
List<CharSequence> texts = event.getText();
if (!texts.isEmpty())
{
for (CharSequence s : event.getText()) {
sb.append(s);
}
if(sb.toString().equals("Incoming video call"))
Log.d( "onAccessibilityEvent", "whatsapp video call" );
}
}
}
}
#Override
public void onInterrupt() {
}
}
I don't think you can do what you want. Using the AccessibilityService you can know when the video call comes in:
#Override
public void onAccessibilityEvent( AccessibilityEvent event )
{
if(event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)
{
if(event.getPackageName().equals("com.whatsapp"))
{
StringBuilder sb = new StringBuilder();
List<CharSequence> texts = event.getText();
if (!texts.isEmpty())
{
for (CharSequence s : event.getText())
{
sb.append(s);
}
if(sb.toString().equals("Incoming video call"))
{
Log.d( "onAccessibilityEvent", "whatsapp video call" );
}
}
}
}
}
However, I've never been able to answer the call programmatically. The question at How can incoming calls be answered programmatically in Android 5.0 (Lollipop)? does a great job of enumerating all possible options, but most require root and/or being a system app.
You can use sendKeyDownUpSync method from Instrumentation class.
Instrumentation inst = new Instrumentation();
inst.sendKeyDownUpSync(KeyEvent.KEYCODE_HEADSETHOOK);
if this code didn't work, try to use another KeyEvent to find the correct one.
You can see the list of KeyEvent from this link : https://developer.android.com/reference/android/view/KeyEvent.html
You can check more info in from here : Instrumentation
A classic way to achieve this is to observe notifications using the NotificationListenerService and act on the relevant action of the notification.
Related
I am using Codenameone and ZXing to read a QRCode. When I call the Scanner, my mobile opens the QRCode reader application and I get to read the QRCode except that when android takes me back to my app it goes through init then start statuses. Which moves me back to the login form of my application instead of continuing filling the form that I was in.
Any help on what to do to stay in the same form? Is there something I'm doing wrong? Thanks in advance.
EverproX.addMessage("Before Scan\n");
CodeScanner.getInstance().scanQRCode(new ScanResult() {
public void scanCompleted(String contents, String formatName, byte[] rawBytes) {
EverproX.addMessage("Scan Completed "+contents);
}
public void scanCanceled() {
EverproX.addMessage("Scan Cancelled");
}
public void scanError(int errorCode, String message) {
EverproX.addMessage("Scan Error "+errorCode+" "+message);
}
});
EverproX can be seen as a log class.
By analyzing our log we can say that as soon as we call the CodeScanner.getInstance().scanQRCode() the application is called for 'Destroy'. Then after the scanning is done it goes again through the init and start. It never goes into the scanComplete scanCanceled or scanError Callbacks.
Is it normal that the App is destroyed upon call of CodeScanner? Many thanks.
Inside your codenameone project, you should find a class named (for example MyApp.java) based on your app's name, modify the code to read something like similar to this:
public class MyApp {
private Form current;
public void init(Object context) {
// Pro users - uncomment this code to get crash reports sent to you automatically
Display.getInstance().addEdtErrorHandler(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
evt.consume();
Log.p("Exception in AppName version " + Display.getInstance().getProperty("AppVersion", "Unknown"));
Log.p("OS " + Display.getInstance().getPlatformName());
Log.p("Error " + evt.getSource());
Log.p("Current Form " + Display.getInstance().getCurrent().getName());
Log.e((Throwable) evt.getSource());
Log.sendLog();
}
});
}
public void start() {
if (current != null) {
current.show();
return;
}
new StateMachine("/theme");
}
public void stop() {
current = Display.getInstance().getCurrent();
}
public void destroy() {
current = null;
}
}
I want to scan for Bonjour devices (_http._tcp.local.) every 5 seconds and get a arraylist with the found devices (the names, so strings). I need to do it in a service (and in a background thread).
Now I'm making every 5 seconds a new instance of JmDNS (JmDNS.create()) and that leaks memory ;).
I think there must be a better way to do it, but I don't know it... Who can help me?
try {
final JmDNS jm;
ArrayList<String> foundDevices = new ArrayList<String>();
jm = JmDNS.create();
jm.addServiceListener("_http._tcp.local.", listener = new ServiceListener() {
#Override
public void serviceAdded(ServiceEvent event) {
jm.requestServiceInfo(event.getType(), event.getName(), 1);
}
#Override
public void serviceRemoved(ServiceEvent event) {
}
#Override
public void serviceResolved(ServiceEvent event) {
JSONObject obj = null;
ServiceInfo info = event.getInfo();
//Log.e("TCLogging", "RAW: " + info);
String Name = info.getName();
foundDevices.add(Name);
} catch (Exception e) {
Log.e("TCLogging", "Error");
}
}
});
ServiceInfo serviceInfo = ServiceInfo.create("_http._tcp.", "TC_" + android.os.Build.MODEL, 0, "AndroidApp");
jm.registerService(serviceInfo);
} catch (Exception e) {
Log.e("TCLogging", e.toString());
}
You could just call JmDNS.list(String type) every N seconds, which would return the ServiceInfo for the services it found. This first call will take time (you can control that via an overload of list(String type, long timeout)), default seems to be 6secs.
Something I didn't know about JmDNS was that you get notified when a device is discovered or disappears in the network. I wanted to scan every N seconds to see what devices are in the network. But it's much easier (and less resource intensive) to just wait until you get notified of any device changes.
The accepted answer did work for me to achieve the scan every N seconds, but it's not the most ideal way to do it!
I would like to know the purpose of foloowing two files:
frameworks/base/core/java/android/app/IActivityWatcher.aidl
[description: Callback interface to watch the user's traversal through activities.]
frameworks/base/core/java/android/app/IProcessObserver.aidl
[no description]
I am trying to build an app wherein user can decide which apps can be run during particular period of time (say, from 10am till 4pm).
Is there any way where my app will get notified if one the apps specified by the user starts? This way my app can send kill command (I am assuming that root access is available.)
It seems that IActivityWatcher has been removed beginning with JellyBean, in order to monitor which Activity is running foreground, you can use IProcessObserver as following:
mActivityManagerNative = ActivityManagerNative.getDefault();
if (mActivityManagerNative != null) {
try {
mActivityManagerNative.registerProcessObserver(mProcessObserver);
} catch (RemoteException e) {
Log.e("TAG", "onCreate() RemoteException!");
}
}
private IProcessObserver.Stub mProcessObserver = new IProcessObserver.Stub() {
#Override
public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {
doWhatUWantHere();
}
#Override
public void onImportanceChanged(int pid, int uid, int importance) {
}
#Override
public void onProcessDied(int pid, int uid) {
}
};
P.S.
You can use following code snippets to get the package name of foreground running Activity:
private String getForegroundPackage() {
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<RecentTaskInfo> taskInfo = am.getRecentTasks(1,
ActivityManager.RECENT_IGNORE_UNAVAILABLE);
return taskInfo.isEmpty()
? null : taskInfo.get(0).baseIntent.getComponent().getPackageName();
}
In the Android app that I'm working on, I'd like to be able to detect when a new status bar notification appears, regardless of if it was caused by my app. To be more specific, I want to count the number of notifications in a given time frame.
Is this even possible, and if so, how?
Actually, it is possible, I use it in my app.
For Android 4.2 and below:
You need to register an AccessibilityService and make sure the user enables the service.
Example for a service:
public class InstantMessenger extends AccessibilityService {
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
if (event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {
//Do something, eg getting packagename
final String packagename = String.valueOf(event.getPackageName());
}
}
#Override
protected void onServiceConnected() {
if (isInit) {
return;
}
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
info.eventTypes = AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;
setServiceInfo(info);
isInit = true;
}
#Override
public void onInterrupt() {
isInit = false;
}
}
Example for checking if your Service is activated
For Android 4.3 and above:
Use the Notification Listener API
The new Notification Listener API in Android 4.3 enables you to do this.
With this there is less need for the accessibility hack. It also allows you to dismiss notifications.
How can you read data, i.e. convert simple text strings to voice (speech) in Android?
Is there an API where I can do something like this:
TextToVoice speaker = new TextToVoice();
speaker.Speak("Hello World");
Using the TTS is a little bit more complicated than you expect, but it's easy to write a wrapper that gives you the API you desire.
There are a number of issues you must overcome to get it work nicely.
They are:
Always set the UtteranceId (or else
OnUtteranceCompleted will not be
called)
setting OnUtteranceCompleted
listener (only after the speech
system is properly initialized)
public class TextSpeakerDemo implements OnInitListener
{
private TextToSpeech tts;
private Activity activity;
private static HashMap DUMMY_PARAMS = new HashMap();
static
{
DUMMY_PARAMS.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "theUtId");
}
private ReentrantLock waitForInitLock = new ReentrantLock();
public TextSpeakerDemo(Activity parentActivity)
{
activity = parentActivity;
tts = new TextToSpeech(activity, this);
//don't do speak until initing
waitForInitLock.lock();
}
public void onInit(int version)
{ //unlock it so that speech will happen
waitForInitLock.unlock();
}
public void say(WhatToSay say)
{
say(say.toString());
}
public void say(String say)
{
tts.speak(say, TextToSpeech.QUEUE_FLUSH, null);
}
public void say(String say, OnUtteranceCompletedListener whenTextDone)
{
if (waitForInitLock.isLocked())
{
try
{
waitForInitLock.tryLock(180, TimeUnit.SECONDS);
}
catch (InterruptedException e)
{
Log.e("speaker", "interruped");
}
//unlock it here so that it is never locked again
waitForInitLock.unlock();
}
int result = tts.setOnUtteranceCompletedListener(whenTextDone);
if (result == TextToSpeech.ERROR)
{
Log.e("speaker", "failed to add utterance listener");
}
//note: here pass in the dummy params so onUtteranceCompleted gets called
tts.speak(say, TextToSpeech.QUEUE_FLUSH, DUMMY_PARAMS);
}
/**
* make sure to call this at the end
*/
public void done()
{
tts.shutdown();
}
}
Here you go . A tutorial on using the library The big downside is that it requires an SD card to store the voices.
A good working example of tts usage can be found in the "Pro Android 2 book". Have a look at their source code for chapter 15.
There are third-party text-to-speech engines. Rumor has it that Donut contains a text-to-speech engine, suggesting it will be available in future versions of Android. Beyond that, though, there is nothing built into Android for text-to-speech.
Donut has this: see the android.speech.tts package.