I have a BroadcastReceiver (Android 4.1) which must test for the existence of a file located in the external storage area. The receiver doesn't need to read or write to the file; just test for its existence.
I haven't found anything in the Android documentation which indicates that BroadcastReceivers cannot access external files, yet the code below always returns false.
The logcat output shows getExternalStorageState() returns "mounted" and I can access the file using an ordinary App, just not in the Receiver. No exceptions are thrown.
public class FileCheckReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
boolean b = checkFile();
Log.d(TAG, "FileCheckReceiver: " + b);
}
boolean checkFile() {
String state = Environment.getExternalStorageState();
Log.d(TAG, "FileCheckReceiver, Environment.getExternalStorageState: " + state);
String name = "file.txt";
File f = new File(Environment.getExternalStorageDirectory() + "/" + name);
try
{
if (f.exists()) {
System.out.println(f.getCanonicalPath().toString());
return true;
}
}catch(Exception e) {
e.printStackTrace();
}
return false;
}
}
Are BroadcastReceivers stopped from accessing files?
A good approach would to be start a new Service from the BroadcastReceiver to handle tasks that you wish to perform.
Other things:
Make sure you have declared the receiver in manifest.xml
Also you need to consider the following as well.
As of Android 3.1 the Android system will by default exclude all BroadcastReceiver from receiving intents if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu (in Manage Application).
This is an additional security features as the user can be sure that only the applications he started will receive broadcast intents.
I eventually discovered that System Apps (which my app was) do not have any access to files stored on external storage.
Moving my BroadcastReceiver to another (non-system) APK fixed the problem.
Related
I need BLUETOOTH PRIVILEGED permission to autopair device
How to get BLUETOOTH_PRIVILEGED permission to autopair device in a roted device
without putting it at system app ?
I am trying to make a programmatically auto repair with one devices that I have already displayed in ListView without showing the "Pair Dialog"
IntentFilter filter = new IntentFilter("android.bluetooth.device.action.PAIRING_REQUEST");
registerReceiver(new PairingRequest(), filter);
//receiver
public static class PairingRequest extends BroadcastReceiver {
public PairingRequest() {
super();
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.bluetooth.device.action.PAIRING_REQUEST")) {
try {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
int pin = intent.getIntExtra("android.bluetooth.device.extra.PAIRING_KEY", 0);
//the pin in case you need to accept for an specific pin
Log.d("PIN", " " + intent.getIntExtra("android.bluetooth.device.extra.PAIRING_KEY",0));
//maybe you look for a name or address
Log.d("Bonded", device.getName());
byte[] pinBytes;
pinBytes = (""+pin).getBytes("UTF-8");
device.setPin(pinBytes);
device.setPairingConfirmation(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
but after is calling device.setPairingConfirmation(true); it goes on exception with this error java.lang.SecurityException: Need BLUETOOTH PRIVILEGED permission: Neither user 10069 nor current process has android.permission.BLUETOOTH_PRIVILEGED.
I have made my search and all the suggestions was to put the app in system/app but I can't put there cause I need to make updates in the future.
My device that I am using is rooted and the app is in "data/app" path
Any suggestion would be an help.
Thanks a lot!
I have recently replaced all my service to foreground services and JobIntentService since there are some background execution limits (https://developer.android.com/about/versions/oreo/background) in oreo and above. As per documentation, JobIntentService acts like Intent Service for Android 7 & below and acts like JobScheduler for Android 8 & above. I have noticed there is an issue in new JobIntentService provided by Google.
Android 8 & above:
There is a crash happening continuously in android 8 and above. There was a ticket raised here mentioning about the same issue https://issuetracker.google.com/issues/63622293 and I have added a temp fix suggested by few geeks.
Android 7 & below:
JobIntentService which acts like Intent Service is not getting stopped once the work is done.
I have implemented JobIntentService within a service which triggers whenever some action is performed by a user.
Code
public class SampleJobIntentService extends FixedJobIntentService {
public static void postData(Context context, String data) {
Intent intent = new Intent(context, SampleJobIntentService.class);
intent.setAction(INITIAL_ACTION);
intent.putExtra(SAMPLE_ID, data);
SampleJobIntentService.enqueueWork(context,intent);
}
public static void enqueueWork(Context context, Intent work) {
SampleJobIntentService.enqueueWork(context, SampleJobIntentService.class, JOB_ID, work);
#Override
protected void onHandleWork(#NonNull Intent intent) {
if (intent != null) {
SampleRequest sampleRequest = requests.get(intent.getAction());
if (sampleRequest != null) {
try {
// perform some networking operations
} catch (Exception ex) {
Log.d("Error for intent ");
}
Log.i("send action ");
} else
Log.e("action not found for ");
}
}
}
To avoid the crash with JobIntentService, I took few references from https://issuetracker.google.com/issues/63622293
public abstract class FixedJobIntentService extends JobIntentService {
#Override
GenericWorkItem dequeueWork() {
try {
return new FixedGenericWorkItem(super.dequeueWork());
} catch (SecurityException ignored) {
doStopCurrentWork();
}
return null;
}
private class FixedGenericWorkItem implements GenericWorkItem {
final GenericWorkItem mGenericWorkItem;
FixedGenericWorkItem(GenericWorkItem genericWorkItem) {
mGenericWorkItem = genericWorkItem;
}
#Override
public Intent getIntent() {
if (mGenericWorkItem != null) {
return mGenericWorkItem.getIntent();
}
return null;
}
#Override
public void complete() {
try {
if (mGenericWorkItem != null) {
mGenericWorkItem.complete();
}
} catch (IllegalArgumentException ignored) {
doStopCurrentWork();
}
}
}
}
Well..., Its a lot big theory...!! It would not be able to put it all here. I will try my best which will make some your concepts clear.
I have already lost my 2 complete years in reading google documentations... Which are use-less... With no proper documentation and with no proper sample codes for its developers..!! So i mention this in every of my posts on stack-overflow, As it will help to save time of others..!!
It looks you are a good programmer; just need some hints to your posted question :
Hint-1 :
YOU :- I have recently replaced all my service to foreground services and
JobIntentService
foreground service :
If you need ALL THE TIME RUNNING PROCESS; WHICH WILL NEVER END... ONCE IT IS STARTED it is used in service which returns START_STICKY from its OnStartCommand. Which is again not advised to use as if you want to implement it at any cost ... then you will have to use a notification with setOngoing(true) Which end user would not be able to swipe away your notification, it will remain there forever....
Use of the foreground service :
There has been restrictions on receivers too; above Oreo onwards and you can not use all the receivers and intent actions by declaring it in manifest and by just making a receiver... I advice to just use BootComplete permission and use a single receiver which receives the boot_completed intent and calls a service if below O and calls a foreground service above O. Now from that foreground service you implement the runtime receivers for all and unregister it in Ondestroy methods. I have never found an official sample code for implementing runtime receiver and finally i have implemented it successfully by many months hard-work... Yes it was not a smart work due to google
When to use foreground service :
Only if you want to implement broadcast receivers.... If you do not want to implement any broadcast receivers; STAY AWAY.......
Hint-2 :
YOU :- I have recently replaced all my service to foreground services and
JobIntentService
** service has its quality of :**
Just doing a very tiny work... and just exit... it has to be exited by StopSelf()... Again, Services can cause data-loss if called multiple times... As same service thread can be run more than once... Again if you want a service to do a lot of work... Use START_STICKY... But again it is not recommended and i have suggested already, when to use it in Hint 1.
** Intentservice has its quality of :**
Doing a relatively long running tasks and it has property of execution serially only If you again and again calls the same intentService, then all calls will be kept in a queue and will be executed one by one after finishing one by one. Which is not the case in service as depicted above. It ends on its own... no need to end it by a developer..!!
** Unique Quality of all :**
Once they are crashed android can stop them calling in future without notifying you as it crashes the app. Need to be handled them with try-catch-exception to avoid crash. Again... If you are implementing threads within services then try-catch-exception will not save your application from being crashing...
** THEN WHAT THE HELL & HOW TO IMPLEMENT IT THEN :**
Use FireBaseJobScedular :-
Easy to use
Uses simple JobService
Can run longer or smaller time tasks... EVEN ALL THE TIME RUNNING TASK
EVEN SUPPORTED BY NON STANDARD COMPANIES like vivo, mi, oppo, one+3, ... which takes stock-android makes changes to it and gives names like FunTouchOs, ColorOs, OxygenOs
Just need to Do change battery settings to "Do not optimise this app"
Yes google supports it officially and recommends to use it
It Creates the instance of GooglePlyService and runs within it, And obviously non-standards companies too would not restrict google apps from being doing its tasks.
Works on Oreo .., Even i have tested it on Android P and works below Android version 5.0 as AlarmManager tasks.
Still i recommends to use minsdk above 16, target sdk 26 as if in case you wants to upload your app to google play it is compulsory now and that news would have been heard you. and compile sdk 26.
Just Bind Your JobService in manifest and use a single line permission of receive_boot_complete
Just schedule it ... And it will be started on every device in market from every manufacturer... even on cold boot and hot boot
It minimises a lot, lot and lot of code and you can focus on actual tasks.
Once task is finished you can return false to indicate task has been finished and it will end the JobService.
Why i am suggesting because i am CTO of a well-UNKNOwn company and has been experienced the problems caused by foreground service across the many types of android phone manufacturers... It is not the Apple and ios so we had to experienced it. Remain developer since past 18 years and i mostly codes today too... in all of the development projects and its development strategies are thought by me only.
Correct me ... too... As you have not mentioned what your tasks and
project is related to... and what you exactly wants to be done in a
foreground service and intent-service... Let me know..., It would be my pleasure to help you. It is a general theoretical answer rather than what you wants.... But for giving you actual answer i will need exact your project scope..
JobIntentService which acts like Intent Service is not getting stopped once the work is done
The issue is in your extended class FixedJobIntentService dequeueWork method.
Try changing it to something like below
GenericWorkItem superValue = super.dequeueWork();
if (superValue != null) {
return new FixedGenericWorkItem(superValue);
}
return null;
Looking at the JobIntentSerivce code, Work Items processor logic is below, i.e until there are no work items left in the queue all items are processed (i.e onHandleWork is called for each item)
while ((work = dequeueWork()) != null) {
if (DEBUG) Log.d(TAG, "Processing next work: " + work);
onHandleWork(work.getIntent());
if (DEBUG) Log.d(TAG, "Completing work: " + work);
work.complete();
}
Issue in your implementation is after processing the first work item, the super.dequeueWork() returns null, which you are not taking care of and just sending a new FixedGenericWorkItem object passing null value. You might observe that a null value is passed to your onHandleWork in your subsequent calls.
Hope this helps resolve your issue.
I think you just need this much of a code. Create a new Class MyJobIntentService and write this much of a code and call postData() to start your service.
public class MyJobIntentService extends JobIntentService {
public static void postData(Context context, String data) {
final Intent intent = new Intent(context, MyJobIntentService.class);
intent.setAction(INITIAL_ACTION);
intent.putExtra(SAMPLE_ID, data);
enqueueWork(context, MyJobIntentService.class, 1000, intent);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Ln.d("Cancelled service");
super.onDestroy();
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
if (intent != null) {
final SampleRequest sampleRequest = requests.get(intent.getAction());
if (sampleRequest != null) {
try {
// perform some networking operations
} catch (Exception ex) {
Log.d("Error for intent ");
}
Log.i("send action ");
} else {
Log.e("action not found for ");
}
}
}
}
And make sure to add your service in manifest file
<service
android:name="service.MyJobIntentService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE" />
I have an Android app and I want to monitor a folder. I made a service(I want to monitor the folder non-stop, even if the user kill the app) and I put the folder's path in the extras of the Intent. In the service I have a FileObserver that should monitor my folder and trigger an event whenever a file is created inside the folder. The problem is that event is never triggered.
Am I doing something wrong? Thanks!
#Override
public int onStartCommand(Intent intent, int flags, int startId){
String mainFolder = intent.getStringExtra("mainFolder");
Toast.makeText(getApplicationContext(), "Service start! Main folder is: " + mainFolder, Toast.LENGTH_LONG).show();
FileObserver observer = new FileObserver(mainFolder) {
#Override
public void onEvent(int event, String path) {
if (path == null) {
return;
}
if (FileObserver.CREATE == event) {
Toast.makeText(getApplicationContext(), "This file was creted: " + path, Toast.LENGTH_LONG).show();
}
}
};
observer.startWatching();
return START_REDELIVER_INTENT;
}
Quoting the documentation for FileObserver:
Warning: If a FileObserver is garbage collected, it will stop sending events. To ensure you keep receiving events, you must keep a reference to the FileObserver instance from some other live object.
Your FileObserver instance is eligible for garbage collection as soon as onStartCommand() returns, as you are not holding it in a field, but in a local variable.
Also, bear in mind that services do not run forever.
I'm encountering such a scenario in Android.
App A has permission PERM to get some information. Instead of directly getting this information, it sends an intent to one BroadCastReceiver inside App B (of course B has PERM). In order to ensure all such apps like A has the permission, I use a context.checkCallingPermission (with the help of this answer).
However it always fails.
public void onReceive(Context context, Intent intent) {
String info;
String perm = Manifest.permission.READ_PHONE_STATE;
Log.i(TAG, "callPid="+ Binder.getCallingPid()+" myPid="+ Process.myPid()); /// SAME PID
if (context.checkCallingPermission(perm) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "not granted " + perm);
info = "denied perm " + perm;
} else {
Log.i(TAG, perm + " already granted");
info = dumpDeviceInfoImpl(context);
}
}
Specially, the comment line always return SAME pid (B's), when I send intent from A. I can confirm A and B have different PIDs.
update
Previously I was thinking it is due to BroadCastReceiver, so I tried to startActivity from A and then start an activity in B. Once again, during checkCallingPermission, it fails again. Surprisingly, still returning the SAME pid.
So what's the correct way to use checkCallingPermission?
use this methdos
checkCallingPermission(Context context, String permission, String packageName)
Checks whether the IPC you are handling has a given permission and whether the app op that corresponds to this permission is allowed.
I want to uninstall my application on button click. For this I am using following code.
Uri packageURI = Uri.parse("package:"+packageName);
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
startActivity(uninstallIntent);
It gives me result, but I want to delete directly without click on "Ok" button of dialog with message "This application will be Uninstalled".
I just want uninstalling application directly.
Uninstalling without user confirmation is not allowed to 3rd party applications.
As xDragonZ points out, a root process can crudely do this by literally removing the directory and leaving the package manager to deal with the loss, but that's not a very widely deployable solution, since AFAIK no devices ship with that capability for apps to run their own root helper process - that's a risky aftermarket modification.
Yes it is possible to uninstall a package in Android. Moreover you can also skip asking user to press OK button on uninstall screen. You can do it by using Accessibility service in Android.
public class MyAccessibilityService extends AccessibilityService {
private static final String TAG = MyAccessibilityService.class
.getSimpleName();
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.i(TAG, "ACC::onAccessibilityEvent: " + event.getEventType());
//TYPE_WINDOW_STATE_CHANGED == 32
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event
.getEventType()) {
AccessibilityNodeInfo nodeInfo = event.getSource();
Log.i(TAG, "ACC::onAccessibilityEvent: nodeInfo=" + nodeInfo);
if (nodeInfo == null) {
return;
}
List<AccessibilityNodeInfo> list = nodeInfo
.findAccessibilityNodeInfosByViewId("com.android.settings:id/left_button");
for (AccessibilityNodeInfo node : list) {
Log.i(TAG, "ACC::onAccessibilityEvent: left_button " + node);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
list = nodeInfo
.findAccessibilityNodeInfosByViewId("android:id/button1");
for (AccessibilityNodeInfo node : list) {
Log.i(TAG, "ACC::onAccessibilityEvent: button1 " + node);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
#Override
public void onServiceConnected() {
Log.i(TAG, "ACC::onServiceConnected: ");
}
#Override
public void onInterrupt() {
// TODO Auto-generated method stub
}
}
You should first look into the Android native PackageInstaller. I would recommendating you to update all the code you use.
Next step is to inspect PackageInstaller which is an normal class. You will find that uninstall function there. The bad news is that this needs Manifest.permission.DELETE_PACKAGES permission and its only granted to system apps. This means that this is not available directly to other developers. But we can access it using device owner permission.
This requires:
Android 6.0 or newer
Device owner permission to uninstall the package
Generally the DELETE_PACKAGES permission says:
Allows an application to delete packages.
Not for use by third-party applications.
Once your app gets the device owner permission, you can uninstall an package like this:
String appPackage = "com.your.app.package";
Intent intent = new Intent(getApplicationContext(),
getApplicationContext().getClass()); //getActivity() is undefined!
PendingIntent sender = PendingIntent.getActivity(getActivity(), 0, intent, 0);
PackageInstaller mPackageInstaller =
getActivity().getPackageManager().getPackageInstaller();
mPackageInstaller.uninstall(appPackage, sender.getIntentSender());
The code used available here:
PackageInstaller "Silent install and uninstall of apps by Device Owner” - Android M Preview