android Accessibility-service suddenly stopped triggering events - java

I have an AccessibilityService which was working fine but for some reason during development it stopped working. I can't seem to find that reason. Please have a look at my code and tell why it isn't working.
public class MyServicee extends AccessibilityService {
public static final String TAG = "volumeMaster";
#TargetApi(Build.VERSION_CODES.KITKAT)
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
List<CharSequence> eventText;
Log.v(TAG, "***** onAccessibilityEvent");
final int eventType = event.getEventType();
switch (eventType) {
case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
break;
}
if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED) {
}
}
private String processUSSDText(List<CharSequence> eventText) {
for (CharSequence s : eventText) {
String text = String.valueOf(s);
if (true) {
return text;
}
}
return null;
}
#Override
public void onInterrupt() {
Log.v(TAG, "***** onInterrupt");
}
#TargetApi(Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onServiceConnected() {
Log.v(TAG, "***** onServiceConnected");
AccessibilityServiceInfo info = getServiceInfo();
info.eventTypes =
AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED
| AccessibilityEvent.TYPE_VIEW_CLICKED
| AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.packageNames = new String[]{"com.whatsapp"};
info.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
setServiceInfo(info);
super.onServiceConnected();
}
}
Here's the relevant part of Manifest:
<service android:name=".MyServicee"
android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
android:enabled="true">
<intent-filter>
<action android:name="android.accessibilityservice.AccessibilityService" />
</intent-filter>
<meta-data android:name="android.accessibilityservice"
android:resource="#xml/myservice" />
</service>
Here's myserviceconfig.xml:
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeViewClicked|typeNotificationStateChanged|typeWindowStateChanged"
android:accessibilityFeedbackType="feedbackAllMask"
android:canRetrieveWindowContent="true"
android:accessibilityFlags="flagIncludeNotImportantViews|flagRequestFilterKeyEvents"
android:notificationTimeout="1"
android:packageNames="com.whatsapp"
android:settingsActivity="#string/app_name" />
The code attempts to detect when the user has started a call recording service.

There are a few problems with your configuration:
First in your onServiceConnected function, you overwrite the system constructed accessibility info.
AccessibilityServiceInfo info = getServiceInfo();
info.eventTypes =
AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED
| AccessibilityEvent.TYPE_VIEW_CLICKED
| AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
info.packageNames = new String[]{"com.whatsapp"};
info.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
setServiceInfo(info);
super.onServiceConnected();
This entire block of code is unnecessary and is all accomplished by the similar lines in your serviceConfig XML file. Just omit it, if you can't omit it, there is a problem with your configuration, though everything outside of this seems to be fine.
Now, speaking of letting your service_config xml file speak for itself, let's talk about a couple of lines in here:
android:notificationTimeout="1"
A notification timeout of 1 MS is essentially worthless.
android:packageNames="com.whatsapp"
Do you really want to limit accessibility events to just one application?
android:settingsActivity="#string/app_name"
This is an absolutely invalid value for the settingsActivity property. The settings activity should be the name of an activity class within your application. EX: com.yourpackage.SettingsActivity. This property can be safely omitted.
Aside from this information it is fairly easy to get accessibility services in a completely stale state. Have a daemon service, running in the background, keeping your service form starting but NOT actually doing productive things. The only way to fix this is to restart your device. Sometimes you even have to uninstall your package and then restart your device and then reinstall your package.

Related

How to solve Android 12 cannot use MqttAndroidClient

In my Android Studio, I would like to connect the Mqtt Android client to my laptop host (in the same machine). I make it similar to this guide
https://www.hivemq.com/blog/mqtt-client-library-enyclopedia-paho-android-service/
Then, I found that the Android 12 (API 32 in my case) may not support the org.eclipse.paho:org.eclipse.paho.android.service:1.1.1 dependency. So, I followed this solution below, by imported the serviceLibrary-release.aar library from github provided instead. (The problem appear in this link was the same of my case)
Android paho mqtt crashes Android 12 - Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE
After that, I ran into another error.
error: constructor MqttAndroidClient in class MqttAndroidClient cannot be applied to given types;
MqttAndroidClient client = new MqttAndroidClient(MainActivity.this, "tcp://10.0.2.2:1883", clientId);
^
required: Context,String,String,Ack
found: MainActivity,String,String
reason: actual and formal argument lists differ in length
So I'm not sure that the library from the solution above can be applied to my old code, or, do I need to modify some code?
Here is my code and the gradle file.
repositories
maven {
url "https://repo.eclipse.org/content/repositories/paho-releases/"
}
Dependencies
implementation files('libs/serviceLibrary-release.aar')
implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5'
Android Manifest (Added permission below)
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<service android:name="info.mqtt.android.service.MqttService"/>
Main Activity
import info.mqtt.android.service.MqttAndroidClient;
public class MainActivity extends AppCompatActivity {
private Button buttonConnect;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonConnect = findViewById(R.id.buttonConnect);
buttonConnect.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String clientId = MqttClient.generateClientId();
Toast.makeText(MainActivity.this, clientId, Toast.LENGTH_SHORT).show();
MqttAndroidClient client = new MqttAndroidClient(MainActivity.this, "tcp://10.0.2.2:1883", clientId);
try {
IMqttToken token = client.connect();
token.setActionCallback(new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
Log.d("Debug", "onSuccess");
Toast.makeText(MainActivity.this, "onSuccess", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.d("Debug", "onFailure");
Toast.makeText(MainActivity.this, "onFailure", Toast.LENGTH_SHORT).show();
exception.printStackTrace();
}
});
} catch (MqttException e) {
e.printStackTrace();
}
}
});
}
}
The error appear in this line (when the button is clicked)
MqttAndroidClient client = new MqttAndroidClient(MainActivity.this, "tcp://10.0.2.2:1883", clientId);
From the error message prompted above. I think that's because the constructor's parameter of this class require a type Ack also, but I have no idea on that.
From output you provided, it seems you only need to specify Ack as the last parameter of your constructor.
It's acknowledgment that you received a message. According to official description, there is two modes available.
First, MqttAndroidClient.Ack.AUTO_ACK, which acknowledge automatically as soon as you received a message.
And then you have MqttAndroidClient.Ack.MANUAL_ACK, which requires you to manually acknowledge by doing MqttAndroidClient.acknowledgeMessage(String)
You can test it simply by adding the auto for now, and if it's ok then you can manually acknowledge yourself with custom rules.

Firebase Notification not sent from console

Firebase notification is not working properly with a specific project.
If I sent notification from the console to all devices it did not work.
If I tried to send a notification via REST. its returns with the below response.
{
"multicast_id": ....,
"success": 0,
"failure": 1,
"canonical_ids": 0,
"results": [
{
"error": "InvalidRegistration"
}
]
}
Update : 2
I have created another project on the firebase console, delete resources and keys from the old project, then I have set up a new android application in the new project.
The result was the same, not receiving any notification The rest result was also the same.
But.
When I add another android application in the same project, then I was able to send notifications from a console-specific to that app, also from the rest API using token.
when I tried the original application token, I have the error. I am not able to find the issue ?. the registration part and initialization part was the same in the application.
Manifest Looks like.
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/purple_700" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="#string/default_notification_channel_id" />
<service
android:name=".CustomFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
App.java
public class App extends Application
{
#Override
public void onCreate() {
super.onCreate();
FirebaseApp.initializeApp(this);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(getString(R.string.default_notification_channel_id),"X1",NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(notificationChannel);
}
}
}
Token Generate.
FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener<String>() {
#Override
public void onComplete(#NonNull Task<String> task) {
Log.d(TAG, "onComplete() called with: task = [" + task + "]");
if(task.isSuccessful())
{
Log.d(TAG, "onComplete() called with: task = [" + task.getResult() + "]");
}
}
});
I have tried the same code with different projects and it's working fine.
I don't know what's wrong!.

How to record data while app is not in focus?

I've created an app that records data usage of an app and writes it to a file on the phones sd card. Now I'm trying to allow this process to run in the background through the use of adb. I want to be able to send a signal/broadcast to the app to write the current data usage. And later be able to send a second signal that writes the data usage and the new time. So that one can look at how much data the app has used.
So far I've tried using adb and sending broadcasts to the app and it seems to be working however I am not able to save the file to the sd card through the use of mediascanner.
This is the function that is run when I send "adb -d shell am broadcast -n com.axel.datatracking/.IntentReceiver --es --start 'com.linku.android.mobile_emergency.app.activity' " to the app.
public void startLog(Context context, SimplifiedAppInfo selectedApp) {
int i = 0;
String name = "dataFile.csv";
Log.d("update", "sort of works maybe");
// make the file if it already exists increment the name by 1
try {
testFile = new File(context.getExternalFilesDir(null), name);
while(testFile.exists()) {
i++;
name = this.makeFileName(i);
testFile = new File(context.getExternalFilesDir(null), name);
}
Log.d("filename", name);
testFile.createNewFile();
} catch (IOException e) {
Log.d("broke", "Unable to write my dood");
}
// try to write to the file
try {
fOut = new FileOutputStream(testFile);
BufferedWriter writer = new BufferedWriter(new FileWriter(testFile, true));
startingDown = selectedApp.getDownbytes();
startingUp = selectedApp.getUpbyts();
startingTime = System.currentTimeMillis();
writer.write("data,up,down\n");
writer.write("Initial,"+selectedApp.getUpbyts()+","+selectedApp.getDownbytes()+"\n");
writer.close();
// refresh the data file
//MediaScannerConnection.scanFile(context, new String[]{this.testFile.toString()}, null, null);
} catch (IOException e) {
Log.d("broke", "cant write to the file");
}
}
This is the function to write the end results that is run by "adb -d shell am broadcast -n com.axel.datatracking/.IntentReceiver --es --end 'com.linku.android.mobile_emergency.app.activity' "
public void endLog(Context context, SimplifiedAppInfo selectedApp) {
// write end results to file
try {
BufferedWriter writer = new BufferedWriter(new FileWriter(testFile, true));
writer.write("End,"+selectedApp.getUpbyts()+","+selectedApp.getDownbytes()+"\n");
float effectiveDown = selectedApp.getDownbytes() - startingDown;
float effectiveUp = selectedApp.getUpbyts() - startingUp;
writer.write("Effective,"+effectiveUp+","+effectiveDown+"\n");
float timePassed = ((float) ((System.currentTimeMillis() - startingTime)/1000));
float avgUp = effectiveUp/timePassed;
float avgDown = effectiveDown/timePassed;
writer.write("Average bytes/sec,"+avgUp+","+avgDown+"\n");
writer.close();
fOut.close();
//MediaScannerConnection.scanFile(context, new String[]{this.testFile.toString()},null, null);
} catch (IOException e) {
Log.d("broke", "the write dont work");
}
}
Broadcast receivers components are not allowed to bind to services.
Edit: I'm open to other solutions besides using a broadcast receiver I just need to be able to log the data while outside of the app and focusing on another app, from the terminal.
Register receiver in manifest and then make some Receiver class, example:
public class CustomReceiver extends BroadcastReceiver {
#Override
public final void onReceive(Context context, Intent intent){
//// here you can start your own service or do logic here
}
here is how to register receiver in Manifest just pick different intent filter:
<receiver android:name="com.example.example.CustomReceiver ">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
And onReceive going to be called whenever phone action will be triggered.
I would advice to read documentation about Intents because Android has a lot of restrictions, per

Can't use backup with Android Backup Service

I'm trying to integrate the Backup Service with my app. It's all working right up to the moment I make the call to:
BackupManager bm = new BackupManager(context);
bm.dataChanged();
I see the following in my Logcat:
W/BackupManagerServiceļ¹• dataChanged but no participant pkg='com.company.app' uid=10102
Here's my implementation of BackupAgentHelper https://gist.github.com/cloakedninjas/fe135cb04bf324e26b0c if it helps...
public class CordovaBackupAgentHelper extends BackupAgentHelper {
static final String FILE_NAME = "gameData.json";
static final String FILES_BACKUP_KEY = "data_file";
#Override
public void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this, FILE_NAME);
addHelper(FILES_BACKUP_KEY, helper);
}
#Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
Log.d(Backup.LOG_TAG, "Backup requested: " + oldState.toString() + " | " + newState.toString());
synchronized (Backup.sDataLock) {
Log.d(Backup.LOG_TAG, "Backup requested: " + data.toString());
super.onBackup(oldState, data, newState);
}
}
#Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
synchronized (Backup.sDataLock) {
Log.d(Backup.LOG_TAG, "Restore given: " + data.toString());
super.onRestore(data, appVersionCode, newState);
}
}
}
I never see my log entry Backup requested. I've checked my Android manifest has the following attribute android:backupAgent="CordovaBackupAgentHelper"
Can anyone shed any light on this?
Update
I've noticed if I change my Manifest to have android:backupAgent="FooBar" I see no errors about undeclared class FooBar, but still see dataChanged but no participant pkg when attempting a backup. So my guess is the error is related to not being able to find my backup agent.
A couple of suggestions:
In your manifest, I think the declaration of the backup agent should either use the full name or the "dot" short form:
android:backupAgent="com.example.project.CordovaBackupAgentHelper"
or
android:backupAgent=".CordovaBackupAgentHelper"
Also, you must have backup enabled in your manifest:
android:allowBackup="true"
Having said that, I doubt these changes with make the warning message go away. I have a backup agent, and am unable to create the warning message you see by changing these declaration to invalid values.
If you are using the Google backup transport, have you registered for the service as described in the Data Backup Guide and added the key to your manifest?
Have you tried to trigger a backup operation using the adb bmgr tool to see if your agent gets called despite the warning message?
So my issue was not putting the attributes onto the correct element :(
I had:
<manifest android:backupAgent="com.cloakedninjas.cordova.plugins.BackupAgentHelper" ...
Instead of:
<application android:backupAgent="com.cloakedninjas.cordova.plugins.BackupAgentHelper" ...

CallBack after Twitter authentication

I'm trying to integrate twitter to my app, but I can't seem to get it to work.
This is my code:
public class OAuthForTwitter extends Activity {
private CommonsHttpOAuthConsumer httpOauthConsumer;
private OAuthProvider httpOauthprovider;
public final static String consumerKey = "{removed}";
public final static String consumerSecret = "{removed}";
private final String CALLBACKURL = "sosInternational:///HierBenIkNu";
private Twitter twitter;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
doOAuth();
}
/**
* Opens the browser using signpost jar with application specific
* consumerkey and consumerSecret.
*/
private void doOAuth() {
try {
httpOauthConsumer = new CommonsHttpOAuthConsumer(consumerKey, consumerSecret);
httpOauthprovider = new DefaultOAuthProvider(
"http://twitter.com/oauth/request_token",
"http://twitter.com/oauth/access_token",
"http://twitter.com/oauth/authorize");
String authUrl = httpOauthprovider.retrieveRequestToken(httpOauthConsumer, CALLBACKURL);
this.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
if (uri != null && uri.toString().startsWith(CALLBACKURL)) {
String verifier = uri
.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
try {
// this will populate token and token_secret in consumer
httpOauthprovider.retrieveAccessToken(httpOauthConsumer,
verifier);
// TODO: you might want to store token and token_secret in you
// app settings!!!!!!!!
AccessToken a = new AccessToken(httpOauthConsumer.getToken(),
httpOauthConsumer.getTokenSecret());
// initialize Twitter4J
twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(consumerKey, consumerSecret);
twitter.setOAuthAccessToken(a);
// create a tweet
Date d = new Date(System.currentTimeMillis());
String tweet = "#OAuth working! " + d.toLocaleString();
// send the tweet
twitter.updateStatus(tweet);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
}
}
}
}
When I'm done authenticating on the Twitter site, it should redirect me back to the app.
But instead, I get this Page not found:
I have this in my AndroidManifest:
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:scheme="sosInternational" android:host="HierBenIkNu"></data>
</intent-filter>
How can I go back to my app with the keys i get back?
Ok, it was quite a dumb mistake.
My <intent-filter> wasn't inside an application..
This is how it is now:
<activity
android:name=".OAuthForTwitter"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:scheme="sosInternational" android:host="OAuthForTwitter"></data>
</intent-filter>
</activity>
This kind off works, it just loads the whole app from start.
Isn't there a way to just 'go back' to the last activity without restarting the whole app?
I have solved this. Not exactly the way you have developed, but a slight different way. Here are the steps describing what i did.
Use webview instead of opening it in web browser: One of the key advantage doing it is , you can track the url redirects.
call setWebViewClient method of your webview and override shouldOverrideUrlLoading method of your class, i have used inner class.
You will have url parameter in your method. Check whether it starts with your own call back url or not, (Note: This url contains User Token and user secret that is necessary for authorization).
After you finish your task, you can hide the activity or remove the webView or any thing you desire.
EDIT : This is the oAuth way usually used in web application, so we don't need xAuth way. (In case other community members don't know)
Hope it will help you.
Your callback URL should be "sosInternational://HierBenIkNu" (instead of "sosInternational:///HierBenIkNu") in the Java code.
private final String CALLBACKURL = "sosInternational://HierBenIkNu";

Categories