Is there a way to check which BroadcastReceivers are declared in the manifest, in runtime?
With PackageManager, you can queryBroadcastReceivers() to find who will all respond to a specific Intent, and with getInstalledPackages(), you can find out the receivers installed per package.
The code would be similar like this, from within an Activity:
// Query all packages that have the BroadcastReceivers...
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
PackageManager pm = getPackageManager();
final List<ResolveInfo> listPkgs = pm.queryBroadcast(mainIntent, 0);
if (listPkgs != null && listPkgs.size() > 0){
for(ResolveInfo resInfo : listPkgs){
// Now resInfo will contain the list of packages that has receivers...
}
}
Thanks, but was not my intention... I wanted to get know if a specific receiver is declared in the running application in runtime, and achieved it like this:
private <Receiver extends CyborgReceiver<?>> boolean checkIfBroadcastReceiverIsRegisteredInManifest(Class<Receiver> receiverType) {
PackageManager pm = application.getPackageManager();
try {
ActivityInfo info = pm.getReceiverInfo(new ComponentName(application, receiverType), PackageManager.GET_RECEIVERS);
return info.enabled;
} catch (NameNotFoundException e) {
return false;
}
}
Pass in the application object as the first argument, you can do this with (Application)context.GetApplicationContext() if you have to, then pass in your class which implements the broadcast receiver class as the second argument e.g. broadcastReceiver.class
public static boolean validateReceiverInManifest(Application application, Class receiverClass) throws PackageManager.NameNotFoundException {
PackageManager pm = application.getPackageManager();
String packageName = application.getPackageName();
PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_RECEIVERS);
ActivityInfo[] receivers = packageInfo.receivers;
String receiverClassName = receiverClass.getName();
for (ActivityInfo activityInfo : receivers) {
if (activityInfo.name.equals(receiverClassName)) {
return true;
}
}
return false;
}
Related
I want to write Firebase's InstanceId service like service in my project. The project is an SDK where the developer who integrates it has the provision to override this service. In this case, I should be able to read the name of the new service specified by the developer with a particular action in their AndroidManifest.xml file.
So the real question here is, how can I read the name of the service declared in the AndroidManifest.xml file with a specific action?
Use below utility method
public static void startService(Context context, String lookupAction) {
Intent serviceIntent = new Intent();
serviceIntent.setAction(lookupAction);
serviceIntent.setPackage("package.of.your.application");
List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(serviceIntent, 0);
if (resInfo != null && !resInfo.isEmpty()) {
ServiceInfo service = resInfo.get(0).serviceInfo;
ComponentName cmpService = new ComponentName(service.applicationInfo.packageName, service.name);
Intent serviceToStart = new Intent(lookupAction);
serviceToStart.setComponent(cmpService);
context.startService(serviceToStart);
} else {
// Handle error
}
}
I will add documentation soon
i am unable to use GetPackageManager in my BroadcastReceiver, i am getting the error "The method getPackageManager() is undefined for the type ReceiverSchedulerDaily". below is my code
public class ReceiverSchedulerDaily extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// clean all app caches
PackageManager pm = getPackageManager();
Method[] methods = pm.getClass().getDeclaredMethods();
for (Method m : methods) {
if (m.getName().equals("freeStorageAndNotify")) {
try {
long desiredFreeStorage = Long.MAX_VALUE;
m.invoke(pm, desiredFreeStorage, null);
} catch (Exception e) {
}
break;
}
}
//
}
}
Instead of the line:
PackageManager pm = getPackageManager();
Use this:
PackageManager pm = context.getPackageManager();
The code you are using was probably used in an Activity before, which is a subclass of Context. But you are using it in a BroadCastReceiver now, which does not extend Context. So you have to use a Context reference instead, to get the reference to the Package Manager system service.
Can the type of application be determined from the ApplicationInfo object ?
By type I mean, determine if is a widget or application.
Alternatively can just a List of of applications which does not include widgets be returned from getPackageManager()?
Below code is what I'm trying to return just applications
but widgets are returned also:
List<ApplicationInfo> appInfoList = context.getPackageManager()
.getInstalledApplications(PackageManager.GET_ACTIVITIES);
I don't believe you can query just the app with or without widgets. But what you can do is to check ActivityInfo.metaData field of every registered broadcast receiver. It contains an instance of Bundle class. All receivers having a widget must have a metadata with the name android.appwidget.provider in that bundle.
final PackageManager pm = act.getPackageManager();
final Intent widgetIntent = new Intent("android.appwidget.action.APPWIDGET_UPDATE");
final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(widgetIntent,
PackageManager.GET_META_DATA);
// optional part (see note below)
for (ResolveInfo receiver : receivers) {
ActivityInfo info = receiver.activityInfo;
if (info.metaData != null) {
boolean hasWidget = info.metaData.containsKey("android.appwidget.provider");
if (hasWidget) {
System.out.println(String.format("Package %s has widget",
info.packageName));
}
}
}
Note: It might even be enough to query all receivers responding to "android.appwidget.action.APPWIDGET_UPDATE" action without checking for metadata, because those receivers are intended for serving a widget. We can assume if there is a receiver with such action, then these is a widget. You don't need the for-loop then.
How do you enable and then disable a component from the manifest in the java code?
taking Pawan approach to more generic implementation:
public static void setComponentState(Context context, String packageName , String componentClassName, boolean enabled)
{
PackageManager pm = context.getApplicationContext().getPackageManager();
ComponentName componentName = new ComponentName(packageName, componentClassName);
int state = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
pm.setComponentEnabledSetting(componentName,
state,
PackageManager.DONT_KILL_APP);
}
i'm using this snippet to check if an app/activity is installed:
public static boolean isIntentAvailable(Context context, String action) {
final PackageManager packageManager = context.getPackageManager();
final Intent intent = new Intent(action);
List<ResolveInfo> list =
packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
public static boolean isScanAvailable(Context context) {
return isIntentAvailable(context, "com.google.zxing.client.android.SCAN");
}
In the above example it checks if the Barcode Scanner App is installed, which works just fine.
However, if i try to check for the Adobe Flashplayer using com.adobe.flashplayer it doesn't work and always returns false.
Is there a better / more reliable method to check for Flash?
Uhm yeah. My code posted above does Intent checking which isn't working for the flashplayer (no public intents i guess).
The more obvious way would be to just use getPackageInfo() which works just fine:
public static boolean isFlashAvailable(Context context) {
String mVersion;
try {
mVersion = context.getPackageManager().getPackageInfo(
"com.adobe.flashplayer", 0).versionName;
Log.d("Flash", "Installed: " + mVersion);
return true;
} catch (NameNotFoundException e) {
Log.d("Flash", "Not installed");
return false;
}
}
(As an added bonus we get the exact version number too)