Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch toast event (from any app) and get toast message

As I understood this is possible, from here Detecting toast messages But I am unable to catch any event with code snippet from the link.

MyAccessibilityService.java

package com.test.toasts2;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.app.Notification;
import android.os.Parcelable;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Toast;

public class MyAccessibilityService extends AccessibilityService {

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        System.out.println("event catched");
        Toast.makeText(this, "catched " + "!", Toast.LENGTH_SHORT).show();
        if(event.getEventType() != AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED)
            return; // event is not a notification

        String sourcePackageName = (String)event.getPackageName();

        Parcelable parcelable = event.getParcelableData();
        if(parcelable instanceof Notification){
            // Statusbar Notification
        }
        else{
            // something else, e.g. a Toast message
            String log = "Message: "+event.getText().get(0)+" [Source: "+sourcePackageName+"]";
            System.out.println(log);
            // write `log` to file...
        }
    }

                 @Override 
                 public void onInterrupt() {
                  // TODO Auto-generated method stub   
                 }

                 @Override
                 protected void onServiceConnected() {
                  // TODO Auto-generated method stub
                  super.onServiceConnected();
                  AccessibilityServiceInfo info = new AccessibilityServiceInfo();
                  info.feedbackType = AccessibilityServiceInfo.DEFAULT;
                  setServiceInfo(info);
                 }


}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.test.toasts2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="15" />

  <application>
  <service android:name=".MyAccessibilityService"
      android:label="label">
    <intent-filter>
      <action android:name="android.accessibilityservice.AccessibilityService" />
    </intent-filter>

  </service>
</application>

</manifest>

Seems like this service is simply not started. What I am doing wrong?

Why I am doing this: I am installing many shortcuts on the stock launcher from my app. I am having the problem that theese shortcuts are placed one over another in one cell (even Sleep 500 did not help). So I am finding a way to install them one by another. But how to know when shortcut was successfully installed? I have found only a message that ics launcher shows to user.

like image 885
POMATu Avatar asked Jun 15 '12 19:06

POMATu


People also ask

How do I make toast notifications?

Instantiate a Toast objectUse the makeText() method, which takes the following parameters: The application Context . The text that should appear to the user. The duration that the toast should remain on the screen.

How do you send a toast message?

Android supports both Kotlin and Java for coding, and we will review the code for both. To initiate a Toast object, the ```makeText()``` method is used. Here you should mention the application context, content of the message, and the duration of the toast message.

How do you show a toast message from flow?

We can show toast message in screen flow using LWC. For this, we can create an LWC component and pass the message, mode and variant attributes from flow based on the success or error scenario. Also this component can be reused.


1 Answers

TYPE_NOTIFICATION_STATE_CHANGED generally refers to NotificationManager and icons placed in the status bar. Nonetheless, the below code should help shed some light as to the origin of a Toast message. On Android 4.0.4 ICS a Toast has a class of android.widget.Toast so getClassName should do the trick.

For what its worth, the change seems to have been made in Android 4.0.3 to add and use the following method in Toast.TN

private void trySendAccessibilityEvent() {
        AccessibilityManager accessibilityManager =
                AccessibilityManager.getInstance(mView.getContext());
        if (!accessibilityManager.isEnabled()) {
            return;
        }
        // treat toasts as notifications since they are used to
        // announce a transient piece of information to the user
        AccessibilityEvent event = AccessibilityEvent.obtain(
                AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
        event.setClassName(getClass().getName());
        event.setPackageName(mView.getContext().getPackageName());
        mView.dispatchPopulateAccessibilityEvent(event);
        accessibilityManager.sendAccessibilityEvent(event);
    }

You can see the Toast class in all versions of Android here.

private final String getEventType(AccessibilityEvent event) {
    switch (event.getEventType()) {
        case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
            return "TYPE_NOTIFICATION_STATE_CHANGED";
        case AccessibilityEvent.TYPE_VIEW_CLICKED:
            return "TYPE_VIEW_CLICKED";
        case AccessibilityEvent.TYPE_VIEW_FOCUSED:
            return "TYPE_VIEW_FOCUSED";
        case AccessibilityEvent.TYPE_VIEW_LONG_CLICKED:
            return "TYPE_VIEW_LONG_CLICKED";
        case AccessibilityEvent.TYPE_VIEW_SELECTED:
            return "TYPE_VIEW_SELECTED";
        case AccessibilityEvent.TYPE_VIEW_SCROLLED:
            return "TYPE_VIEW_SCROLLED";
        case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
            return "TYPE_VIEW_HOVER_EXIT";
        case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
            return "TYPE_VIEW_HOVER_ENTER";
        case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
            return "TYPE_TOUCH_EXPLORATION_GESTURE_START";
        case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
            return "TYPE_TOUCH_EXPLORATION_GESTURE_END";
        case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
            return "TYPE_WINDOW_STATE_CHANGED";
        case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
            return "TYPE_WINDOW_CONTENT_CHANGED";
        case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED:
            return "TYPE_VIEW_TEXT_SELECTION_CHANGED";
        case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
            return "TYPE_VIEW_TEXT_CHANGED";
    }

    return "default";
}

private final String getEventText(AccessibilityEvent event) {
    StringBuilder sb = new StringBuilder();
    for (CharSequence s : event.getText()) {
        sb.append(s);
        sb.append('\n');
    }
    return sb.toString();
}

@Override
public void onAccessibilityEvent(AccessibilityEvent event)
{
    Log.v(TAG, String.format(
        "onAccessibilityEvent: [type] %s [class] %s [package] %s [time] 
        %s [fullscreen] %s [text] %s", getEventType(event), event.getClassName(),
        event.getPackageName(), event.getEventTime(), Boolean.toString(
        event.isFullScreen()), getEventText(event)));

    if (android.os.Build.VERSION.SDK_INT >= 14)
        Log.v(TAG, "Window ID: " + Integer.toString(event.getWindowId()) + ".");
}

private void setServiceInfo(int feedbackType)
{
    final AccessibilityServiceInfo info = new AccessibilityServiceInfo();
    // We are interested in all types of accessibility events.
    info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
    // We want to provide specific type of feedback.
    info.feedbackType = feedbackType;
    // We want to receive events in a certain interval.
    // info.notificationTimeout = EVENT_NOTIFICATION_TIMEOUT_MILLIS;
    // We want to receive accessibility events only from certain packages.
    // info.packageNames = PACKAGE_NAMES;
    setServiceInfo(info);
}

private boolean isInfrastructureInitialized = false;

@Override
public void onServiceConnected()
{   
    if (isInfrastructureInitialized) return;

    // Claim the events with which to listen to.
    setServiceInfo(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);

    // We are in an initialized state now.
    isInfrastructureInitialized = true;
}

Source: personal experience.

like image 167
Tom Avatar answered Sep 19 '22 17:09

Tom