I am trying to build an accessibility service for android and when I am trying to call this function, it always returns 0
class AccessibilityPerform extends Accessibility Service{
#Override
protected void onServiceConnected() {
accessibilityButtonController = getAccessibilityButtonController();
mIsAccessibilityButtonAvailable = accessibilityButtonController.isAccessibilityButtonAvailable();
if (!mIsAccessibilityButtonAvailable) {
return;
}
AccessibilityServiceInfo serviceInfo = getServiceInfo();
serviceInfo.flags |= AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON;
setServiceInfo(serviceInfo);
}
#Override
public void onAccessibilityEvent(AccessibilityEvent accessibilityEvent) {
Log.d("Action",String.valueOf(accessibilityEvent.getAction()));
}
#Override
public void onInterrupt() {}
}
Also I am having minimumSdk version 28 so no problem with FLAG_REQUEST_ACCESSIBILITY_VERSION and I have also set my xml file properly and all flags have been added. So my question is, Is this normal for an accessibilityEvent.getAction() to return 0 everytime. Because I think that it stands for the action which has been performed like AccessbilityNodeInfo.ACTION_CLICK.
Correct me if I am wrong.
Thanks
Related
I'm trying to create the following feature in my application:
I need to check for new notifications in the background (ie even when the application is closed). If the application is running, I want to inform my activity. If the application is not running, a notification should be displayed.
The user can set how often notifications should be checked.
The notification check must start itself after the device is restarted (or when the user installs the application and logs in).
I've been spending half a day on this.
I registered a BroadcastReceiver that captures the successful power-up of the device (BOOT_COMPLETE).
Furthermore, I still don't understand what I should use next (Services or Worker or something else).
How to call check every x minutes (and change minutes if user changes them in settings).
I have probably searched the whole internet and I still can't find anything that would help me. I also read about Services and Workers, but I still don't know what to use.
I will be happy for any help
btw. I get notifications by calling the API using Retrofit (NO Firebase):
private void callAPI(String request) {
call = apiInterface.getAPIData(request);
call.enqueue(new Callback<APIResponse>() {
#Override
public void onResponse(#NotNull Call<APIResponse> call, #NotNull Response<APIResponse> response) {
....
}
#Override
public void onFailure(#NotNull Call<APIResponse> call, #NotNull Throwable t) {
System.out.println(t.toString());
}
});
}
EDIT: The notification check must end when the user logs out. If the user logs in again, the notification check starts again
To receive push notification in background, I use a subclass of FirebaseMessagingService. However, it depends on the rype of the push: containing notification, data or both. Please, refer to the FCM documentation.
OK, I'm testing the following implementation now and it looks good so far
Boot receiver:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()) && !getEmail(context).isEmpty())
startService(context);
}
}
Service utils:
public class utils {
private static final String TAG = "NotificationsChecker";
public static void startService(Context context) {
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(NotificationsWorker.class, getNotificationsFrequency(context), TimeUnit.MINUTES)
.addTag(TAG)
.setConstraints(constraints)
.build();
WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.REPLACE, workRequest);
}
public static void stopService(Context context) {
WorkManager.getInstance(context).cancelAllWorkByTag(TAG);
}
public static void restartService(Context context) {
stopService(context);
startService(context);
}
}
and Notifications worker:
public class NotificationsWorker extends Worker {
private final NotificationsHelper notificationsHelper;
public NotificationsWorker(#NonNull Context context, #NonNull WorkerParameters workerParams) {
super(context, workerParams);
Log.d("Notifications worker", "Worker initiated");
this.notificationsHelper = new NotificationsHelper(context, APIUtils.getAPIService(), newNotifications -> {
if (newNotification == null) {
Log.d("Notifications checker", "newNotification is null");
}
else if (newNotification.getValue() != null && !newNotification.getValue())
Log.d("Notifications checker", "newNotification is not null");
else
Log.d("Notifications checker", "newNotification is undefined");
//newNotification.setValue(newNotifications);
});
}
#NonNull
#Override
public Result doWork() {
notificationsHelper.prepareAPI();
return Result.success();
}
}
I am developing application for monitoring and configuring beacon devices. I need to monitor both iBeacon and Eddystone beacon devices. I have go through the nRF Master control application. Its working perfectly. But I need a source code for that. Is any other option available. Kindly get me the best solution for analysing beacon devices. Thanks in advance.
I would suggest you to use AltBeacon library, which I have used in one of my projects and it's pretty good (I am not associated with it in any way). It provides APIs to interact with beacons.
Here is a sample Activity to get you started:
public class MyActivity extends AppCompatActivity implements
BeaconConsumer,
BootstrapNotifier,
RangeNotifier
{
private RegionBootstrap mRegionBootstrap;
private org.altbeacon.beacon.BeaconManager mAltBeaconManager;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my_application);
mAltBeaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(MyActivity.this);
boolean isBleAvailableAndEnabled;
try {
isBleAvailableAndEnabled = mAltBeaconManager.checkAvailability();
} catch (BleNotAvailableException ex) {
isBleAvailableAndEnabled = false;
}
if (!isBleAvailableAndEnabled) {
// Handle case ...
finish();
}
// Disable Android L scanning on devices with Android 5.0 and above
if (Build.VERSION.SDK_INT >= 21) mAltBeaconManager.setAndroidLScanningDisabled(true);
// Add iBeacon Layout
mAltBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24"));
// Add Eddystone Layout
mAltBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("Eddystone_layout"));
mAltBeaconManager.setBackgroundBetweenScanPeriod(3000); // 3 sec
mAltBeaconManager.setBackgroundScanPeriod(5000); // 5 sec
mAltBeaconManager.bind(MyActivity.this);
// Enable Beacon scanning
mRegionBootstrap = new RegionBootstrap(MyActivity.this, getScanningRegion());
}
#Override
public Context getApplicationContext() {
return (!isFinishing()) ? MyActivity.this : null);
}
#Override
public void onBeaconServiceConnect() {
try {
// Attach beacon range listener
mAltBeaconManager.setRangeNotifier(this);
mAltBeaconManager.startRangingBeaconsInRegion(new Region("Region", null, null, null));
} catch (RemoteException ex) {
// Handle exception
}
}
#Override
public void unbindService(ServiceConnection serviceConnection) {
// Not needed
}
#Override
public boolean bindService(Intent intent, ServiceConnection serviceConnection, int i) {
return false;
}
#Override
public void didEnterRegion(Region region) {
// Handle event
}
#Override
public void didExitRegion(Region region) {
// Handle event
}
#Override
public void didDetermineStateForRegion(int i, Region region) {
// Handle event
}
#Override
public void didRangeBeaconsInRegion(Collection<org.altbeacon.beacon.Beacon> rangingBeacons, Region region) {
// Here you will receive the beacons which are currently in range
}
}
Add this to your Manifest:
<uses-sdk android:minSdkVersion="18" android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
Note: Also, pay attention to this library's limitations, which essentially are Android's software and hardware limitations regarding beacons support.
I can check to see if the burn-in protection property is enabled, but is there a way to tell when burn-in mode is currently active? Like specifically when the screen shifts.
Basically something like "onAmbientModeChanged" for burn in.
Thanks!
In an activity, extend WearableActivity and override onEnterAmbientMode, you have in parameter a Bundle where you can retrieve the property wanted.
(check this WearableActivity)
#Override
public void onEnterAmbient(Bundle ambientDetails) {
super.onEnterAmbient(ambientDetails);
boolean burnIn = ambientDetails.getBoolean(EXTRA_BURN_IN_PROTECTION);
boolean lowBit = ambientDetails.getBoolean(EXTRA_LOWBIT_AMBIENT);
}
In a CanvasWatchFaceService.Engine, override onPropertiesChanged :
#Override
public void onPropertiesChanged(Bundle properties) {
super.onPropertiesChanged(properties);
boolean lowBit = properties.getBoolean(PROPERTY_LOW_BIT_AMBIENT, false);
boolean burnIn = properties.getBoolean(PROPERTY_BURN_IN_PROTECTION, false);
}
Override onAmbientModeChanged(boolean inAMbientMode), it is called whenever the watchface switches from interactive to ambient mode and vice versa :
#Override
public void onAmbientModeChanged(boolean inAmbientMode) {
super.onAmbientModeChanged(inAmbientMode);
if (mState.isAmbient() != inAmbientMode) {
mState.setAmbient(inAmbientMode);
//make your updates on your drawing parameters if needed
invalidate();
}
}
I am working on demo application to get current activity sample using Google Fit. I can get Speed as well as Distance correctly. But it is not returning "in_vehicle" or "biking" state very frequently though I was in the same state. Find attached screenshot for the same. I got speed 59.40KM/H(36.91 M/h) and at that time it not returned "in_vehicle" activity state.
Please provide solution/feedback for the same.
Code :
#Override
public void onDataPoint(DataPoint dataPoint) {
for (Field field : dataPoint.getDataType().getFields()) {
Value val = dataPoint.getValue(field);
if(field.getName().trim().toLowerCase().equals("activity"))
{
if(FitnessActivities.getName(Integer.parseInt(val.toString())).equals("biking"))
{
strState = "Cycling";
}
else if(FitnessActivities.getName(Integer.parseInt(val.toString())).equals("in_vehicle"))
{
strState = "Automotive";
}
else if(FitnessActivities.getName(Integer.parseInt(val.toString())).equals("walking"))
{
strState = "Walking";
}
else
{
strState = "Not Moving";
}
}
}
}
Thanks.
You can find the sample project I created here.
https://github.com/cyfung/ActivityRecognitionSample
Important note: you may NOT get the data as frequent as you requested!
Beginning in API 21, activities may be received less frequently than
the detectionIntervalMillis parameter if the device is in power save
mode and the screen is off.
Key components:
Create the GoogleApiClient in onCreate
mGoogleApiClient =
new GoogleApiClient.Builder(this).addApi(ActivityRecognition.API)
.addConnectionCallbacks(this).addOnConnectionFailedListener(this).build();
Connect and disconnect the api client in onStart and onStop as suggested in Google Api documentation.
#Override
protected void onStart() {
super.onStart();
mGoogleApiClient.connect();
mStatusView.setText("connecting");
}
#Override
protected void onStop() {
super.onStop();
mGoogleApiClient.disconnect();
mStatusView.setText("disconnected");
}
Start activity recognition (should not be called before Google Api connect). Use PendingIntent.getService to create pending intent as callback.
final PendingResult<Status>
statusPendingResult =
ActivityRecognition.ActivityRecognitionApi
.requestActivityUpdates(mGoogleApiClient, DETECT_INTERVAL, PendingIntent
.getService(this, 0, new Intent(this, ActivityDetectionService.class),
PendingIntent.FLAG_UPDATE_CURRENT));
statusPendingResult.setResultCallback(this);
IntentService is the standard method suggested to for callback
public class ActivityDetectionService extends IntentService {
protected static final String TAG = "activityDetectionService";
public ActivityDetectionService() {
super(TAG);
}
#Override
protected void onHandleIntent(Intent intent) {
final ActivityRecognitionResult
activityRecognitionResult =
ActivityRecognitionResult.extractResult(intent);
if (activityRecognitionResult == null) {
return;
}
//process the result here, pass the data needed to the broadcast
// e.g. you may want to use activityRecognitionResult.getMostProbableActivity(); instead
final List<DetectedActivity>
probableActivities =
activityRecognitionResult.getProbableActivities();
sendBroadcast(MainActivity.newBroadcastIntent(probableActivities));
}
}
Register the service in manifest.
<service
android:name=".ActivityDetectionService"
android:exported="false">
</service>
To use the API, you need add the followings in manifest as well.
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"/>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
To get back the data to the activity I used a BroadcastReceiver created in onCreate
mBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
...
}
}
Register and unregister in onResume and onPause respectively.
#Override
protected void onResume() {
super.onResume();
registerReceiver(mBroadcastReceiver, newBroadcastIntentFilter());
}
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(mBroadcastReceiver);
}
As you said you are getting speed correctly. You can put customise code written below.
if (strState.equals("Automotive") && speed == 0.00)
{
strState = "Not Moving";
}
else if (strState.equals("Not Moving") && speed > 5)
{
strState = "Automotive";
}
else
{
strState = "strState";
}
This might not be the correct one but It will be give you nearby state result.
I'm not familiar with google fit api, so the only advice i can give you is to check your code carefully. Is
Integer.parseInt(val.toString())
returning the right int and can
FitnessActivities.getName()
equal "biking", "walking", "in_vehicle" etc.
As i can see from here: https://developers.google.com/fit/rest/v1/reference/activity-types
Biking, In vehicle and Walking are 0, 1 and 7.
Check what FitnessActivities.getName(0) is returning for example, also check is val returning different values or it's returning the same every time.
If you have any problem with your codes you should know what are the code is doing at any line, what methods and functions are returning... Also inform people so they found solutions easier.
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.