How to enable and disable a component? - android

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);
}

Related

Hiding Application Icon programmatically [duplicate]

i had used below code for hide app icon programmatically
try{
PackageManager p = getPackageManager();
p.setComponentEnabledSetting(getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}catch (Exception e) {
e.printStackTrace();
}
Now I want to make icon visible programmatically
Hide app's icon using below code:
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class); // activity which is first time open in manifiest file which is declare as <category android:name="android.intent.category.LAUNCHER" />
p.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Here is how to bring back the app's icon.
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class);
p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Important Edit:
According to docs, as of Android Q (API 29) all app icons will be visible in the launcher no matter what unless:
As of Android Q, at least one of the app's activities or synthesized
activities appears in the returned list unless the app satisfies at
least one of the following conditions:
The app is a system app.
The app doesn't request any permissions.
The tag in the app's manifest doesn't contain any child elements that represent app components.
Additionally, the system hides synthesized activities for some or all
apps in the following enterprise-related cases:
If the device is a fully managed device, no synthesized activities for any app appear in the returned list.
If the current user has a work profile, no synthesized activities for the user's work apps appear in the returned list.
Best Way To Hide Application Icon From Launcher You Can Use
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
In Your Manifest MainActivity
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>
also add uses-feature in Manifest Tag
<uses-feature
android:name="android.software.leanback"
android:required="true" />
To hide icon use this:
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class);
p.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
and to unhide icon:
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class);
p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
IMPORTANT:
It's somehow tricky if you need to do something with main activity in your app when it's hidden. you will face an ActivityNotFoundException. to make it work, you should unhide icon before doing anything to your main activity and hide it again after you are finished.
simple steps:
1-call received here
2-unhide icon
3-launch main activity
4-do your things on main activity
5-hide icon again
Download source code from here (Hide and Unhide the app icon in android programmatically)
MainActivity.java:
package com.deepshikha.hideappicon;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btn_hide;
private static final ComponentName LAUNCHER_COMPONENT_NAME = new ComponentName(
"com.deepshikha.hideappicon", "com.deepshikha.hideappicon.Launcher");
public static int REQUEST_PERMISSIONS = 1;
boolean boolean_permission;
ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
fn_permission();
listener();
}
private void init() {
btn_hide = (Button) findViewById(R.id.btn_hide);
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setTitle("Alert");
progressDialog.setMessage("Please wait");
if (isLauncherIconVisible()) {
btn_hide.setText("Hide");
} else {
btn_hide.setText("Unhide");
}
}
private void listener() {
btn_hide.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_hide:
progressDialog.show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
if (isLauncherIconVisible()) {
btn_hide.setText("Hide");
} else {
btn_hide.setText("Unhide");
}
}
}, 10000);
if (boolean_permission) {
if (isLauncherIconVisible()) {
fn_hideicon();
} else {
fn_unhide();
}
} else {
Toast.makeText(getApplicationContext(), "Please allow the permission", Toast.LENGTH_LONG).show();
}
break;
}
}
private boolean isLauncherIconVisible() {
int enabledSetting = getPackageManager().getComponentEnabledSetting(LAUNCHER_COMPONENT_NAME);
return enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
}
private void fn_hideicon() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Important!");
builder.setMessage("To launch the app again, dial phone number 1234567890");
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
getPackageManager().setComponentEnabledSetting(LAUNCHER_COMPONENT_NAME,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
});
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.show();
}
private void fn_unhide() {
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.deepshikha.hideappicon.MainActivity.class);
p.setComponentEnabledSetting(LAUNCHER_COMPONENT_NAME, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
private void fn_permission() {
if ((ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED)) {
if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.PROCESS_OUTGOING_CALLS))) {
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.PROCESS_OUTGOING_CALLS},
REQUEST_PERMISSIONS);
}
if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.PROCESS_OUTGOING_CALLS))) {
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS},
REQUEST_PERMISSIONS);
}
} else {
boolean_permission = true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSIONS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
boolean_permission = true;
} else {
Toast.makeText(getApplicationContext(), "Please allow the permission", Toast.LENGTH_LONG).show();
}
}
}
}
LaunchAppReceiver.java:
package com.deepshikha.hideappicon;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
/**
* Created by deepshikha on 9/6/17.
*/
public class LaunchAppReceiver extends BroadcastReceiver {
String LAUNCHER_NUMBER = "1234567890";
private static final ComponentName LAUNCHER_COMPONENT_NAME = new ComponentName(
"com.deepshikha.hideappicon", "com.deepshikha.hideappicon.Launcher");
#Override
public void onReceive(Context context, Intent intent) {
String phoneNubmer = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
if (LAUNCHER_NUMBER.equals(phoneNubmer)) {
setResultData(null);
if (isLauncherIconVisible(context)) {
} else {
Intent appIntent = new Intent(context, MainActivity.class);
appIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(appIntent);
}
}
}
private boolean isLauncherIconVisible(Context context) {
int enabledSetting = context.getPackageManager().getComponentEnabledSetting(LAUNCHER_COMPONENT_NAME);
return enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
}
}
Thanks!
this is what I've found so far, unfortunately it's not an answer to the original question, just alternatives
This is the first option, but if your apps require permission and is not useful anymore (at least in Android 10) as #CoronaPintu mentioned here https://stackoverflow.com/a/22754642/1712446 this method works but have many restrictions
private void hideIcon(Context context, Class activityToHide) {
PackageManager packageManager = getPackageManager();
ComponentName componentName = new ComponentName(context, activityToHide);
packageManager.setComponentEnabledSetting(
componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
Using the same method above plus adb command, even is your app require permission this alternative works, but you must have access to devices and connect to a pc, then run this command
to hide:
$adb shell settings put global show_hidden_icon_apps_enabled 0
to show:
$adb shell settings put global show_hidden_icon_apps_enabled 1
Just in case, you cannot run this command from the app
Another option is DevicePolicyManager
private void hideIcon(Context context, Class activityToHide) {
ComponentName componentName = new ComponentName(context, activityToHide);
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(getApplicationContext().DEVICE_POLICY_SERVICE);
devicePolicyManager.setApplicationHidden(componentName, "your.package.name.here", true);
}
This method works, but again we have some restrictions, you need to
enable Device Owner Mode, you can find more info here
To enable this mode you must run this adb command
adb shell dpm set-device-owner my.package.name/.DevAdminReceiver
However you can this command from the app
Runtime.getRuntime().exec("dpm set-device-owner my.package.name/.DevAdminReceiver");
But, if the phone already have set an account, this method going to failed with the next error:
java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device
This feature is no longer supported as of Android Q (API 29). Details have also been added to a previous answer. Your app's icon will be visible unless it satisfies one of the following conditions stated in the docs:
The app is a system app.
The app doesn't request any permissions.
The tag in the app's manifest doesn't contain any child elements that
represent app components.

Android hide/unhide app icon programmatically

i had used below code for hide app icon programmatically
try{
PackageManager p = getPackageManager();
p.setComponentEnabledSetting(getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}catch (Exception e) {
e.printStackTrace();
}
Now I want to make icon visible programmatically
Hide app's icon using below code:
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class); // activity which is first time open in manifiest file which is declare as <category android:name="android.intent.category.LAUNCHER" />
p.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Here is how to bring back the app's icon.
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class);
p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Important Edit:
According to docs, as of Android Q (API 29) all app icons will be visible in the launcher no matter what unless:
As of Android Q, at least one of the app's activities or synthesized
activities appears in the returned list unless the app satisfies at
least one of the following conditions:
The app is a system app.
The app doesn't request any permissions.
The tag in the app's manifest doesn't contain any child elements that represent app components.
Additionally, the system hides synthesized activities for some or all
apps in the following enterprise-related cases:
If the device is a fully managed device, no synthesized activities for any app appear in the returned list.
If the current user has a work profile, no synthesized activities for the user's work apps appear in the returned list.
Best Way To Hide Application Icon From Launcher You Can Use
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
In Your Manifest MainActivity
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
</intent-filter>
</activity>
also add uses-feature in Manifest Tag
<uses-feature
android:name="android.software.leanback"
android:required="true" />
To hide icon use this:
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class);
p.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
and to unhide icon:
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.apps.MainActivity.class);
p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
IMPORTANT:
It's somehow tricky if you need to do something with main activity in your app when it's hidden. you will face an ActivityNotFoundException. to make it work, you should unhide icon before doing anything to your main activity and hide it again after you are finished.
simple steps:
1-call received here
2-unhide icon
3-launch main activity
4-do your things on main activity
5-hide icon again
Download source code from here (Hide and Unhide the app icon in android programmatically)
MainActivity.java:
package com.deepshikha.hideappicon;
import android.Manifest;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btn_hide;
private static final ComponentName LAUNCHER_COMPONENT_NAME = new ComponentName(
"com.deepshikha.hideappicon", "com.deepshikha.hideappicon.Launcher");
public static int REQUEST_PERMISSIONS = 1;
boolean boolean_permission;
ProgressDialog progressDialog;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
fn_permission();
listener();
}
private void init() {
btn_hide = (Button) findViewById(R.id.btn_hide);
progressDialog = new ProgressDialog(MainActivity.this);
progressDialog.setTitle("Alert");
progressDialog.setMessage("Please wait");
if (isLauncherIconVisible()) {
btn_hide.setText("Hide");
} else {
btn_hide.setText("Unhide");
}
}
private void listener() {
btn_hide.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_hide:
progressDialog.show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
progressDialog.dismiss();
if (isLauncherIconVisible()) {
btn_hide.setText("Hide");
} else {
btn_hide.setText("Unhide");
}
}
}, 10000);
if (boolean_permission) {
if (isLauncherIconVisible()) {
fn_hideicon();
} else {
fn_unhide();
}
} else {
Toast.makeText(getApplicationContext(), "Please allow the permission", Toast.LENGTH_LONG).show();
}
break;
}
}
private boolean isLauncherIconVisible() {
int enabledSetting = getPackageManager().getComponentEnabledSetting(LAUNCHER_COMPONENT_NAME);
return enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
}
private void fn_hideicon() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Important!");
builder.setMessage("To launch the app again, dial phone number 1234567890");
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
getPackageManager().setComponentEnabledSetting(LAUNCHER_COMPONENT_NAME,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
});
builder.setIcon(android.R.drawable.ic_dialog_alert);
builder.show();
}
private void fn_unhide() {
PackageManager p = getPackageManager();
ComponentName componentName = new ComponentName(this, com.deepshikha.hideappicon.MainActivity.class);
p.setComponentEnabledSetting(LAUNCHER_COMPONENT_NAME, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
private void fn_permission() {
if ((ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED) ||
(ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.PROCESS_OUTGOING_CALLS) != PackageManager.PERMISSION_GRANTED)) {
if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, android.Manifest.permission.PROCESS_OUTGOING_CALLS))) {
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.PROCESS_OUTGOING_CALLS},
REQUEST_PERMISSIONS);
}
if ((ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.PROCESS_OUTGOING_CALLS))) {
} else {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.PROCESS_OUTGOING_CALLS},
REQUEST_PERMISSIONS);
}
} else {
boolean_permission = true;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == REQUEST_PERMISSIONS) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
boolean_permission = true;
} else {
Toast.makeText(getApplicationContext(), "Please allow the permission", Toast.LENGTH_LONG).show();
}
}
}
}
LaunchAppReceiver.java:
package com.deepshikha.hideappicon;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
/**
* Created by deepshikha on 9/6/17.
*/
public class LaunchAppReceiver extends BroadcastReceiver {
String LAUNCHER_NUMBER = "1234567890";
private static final ComponentName LAUNCHER_COMPONENT_NAME = new ComponentName(
"com.deepshikha.hideappicon", "com.deepshikha.hideappicon.Launcher");
#Override
public void onReceive(Context context, Intent intent) {
String phoneNubmer = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
if (LAUNCHER_NUMBER.equals(phoneNubmer)) {
setResultData(null);
if (isLauncherIconVisible(context)) {
} else {
Intent appIntent = new Intent(context, MainActivity.class);
appIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(appIntent);
}
}
}
private boolean isLauncherIconVisible(Context context) {
int enabledSetting = context.getPackageManager().getComponentEnabledSetting(LAUNCHER_COMPONENT_NAME);
return enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
}
}
Thanks!
this is what I've found so far, unfortunately it's not an answer to the original question, just alternatives
This is the first option, but if your apps require permission and is not useful anymore (at least in Android 10) as #CoronaPintu mentioned here https://stackoverflow.com/a/22754642/1712446 this method works but have many restrictions
private void hideIcon(Context context, Class activityToHide) {
PackageManager packageManager = getPackageManager();
ComponentName componentName = new ComponentName(context, activityToHide);
packageManager.setComponentEnabledSetting(
componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
Using the same method above plus adb command, even is your app require permission this alternative works, but you must have access to devices and connect to a pc, then run this command
to hide:
$adb shell settings put global show_hidden_icon_apps_enabled 0
to show:
$adb shell settings put global show_hidden_icon_apps_enabled 1
Just in case, you cannot run this command from the app
Another option is DevicePolicyManager
private void hideIcon(Context context, Class activityToHide) {
ComponentName componentName = new ComponentName(context, activityToHide);
DevicePolicyManager devicePolicyManager = (DevicePolicyManager) getSystemService(getApplicationContext().DEVICE_POLICY_SERVICE);
devicePolicyManager.setApplicationHidden(componentName, "your.package.name.here", true);
}
This method works, but again we have some restrictions, you need to
enable Device Owner Mode, you can find more info here
To enable this mode you must run this adb command
adb shell dpm set-device-owner my.package.name/.DevAdminReceiver
However you can this command from the app
Runtime.getRuntime().exec("dpm set-device-owner my.package.name/.DevAdminReceiver");
But, if the phone already have set an account, this method going to failed with the next error:
java.lang.IllegalStateException: Not allowed to set the device owner because there are already several users on the device
This feature is no longer supported as of Android Q (API 29). Details have also been added to a previous answer. Your app's icon will be visible unless it satisfies one of the following conditions stated in the docs:
The app is a system app.
The app doesn't request any permissions.
The tag in the app's manifest doesn't contain any child elements that
represent app components.

Android : Intent resolution & ensure BroadcastReceiver is registered / did receive

Based on a checkbox preference I enable a bunch of receivers and I broadcast to them so they schedule a bunch of alarms for themselves. EDIT : The receivers both set up the alarms and wait for the Broadcast from the AlarmManager (as is clear from the onReceive posted).
SettingsActivity
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (newValue instanceof Boolean) {
boolean enable = (Boolean) newValue;
Monitor.enableMonitoring(getApplicationContext(), enable);
return true;
}
return false;
}
Monitor.enableMonitoring
public static void enableMonitoring(Context ctx, boolean enable) {
Resources resources = ctx.getResources();
CharSequence ac_setup_alarm = resources
.getText(R.string.intent_action_setup_alarm);
CharSequence ac_cancel_alarm = resources
.getText(R.string.intent_action_cancel_alarm);
// if only I could do the above in a static way someclass once and for all
Intent i = new Intent("" + (enable ? ac_setup_alarm : ac_cancel_alarm));
if (enable) {
Log.d(_tag, "enable receivers / setup alarms int : " + i);
_enableDisableReceivers(ctx, enable); // enable == true
ctx.sendBroadcast(i);
} else {
Log.d(_tag, "cancel alarms / disable receivers int : " + i);
ctx.sendBroadcast(i);
_enableDisableReceivers(ctx, enable); // enable != true (will disable)
}
}
questions
Why
Intent i = new Intent("" + (enable ? ac_setup_alarm : ac_cancel_alarm)); won't get received while
Intent i = new Intent("" + (enable ? ac_setup_alarm : ac_cancel_alarm), Uri.EMPTY, ctx, BatteryMonitoringReceiver.class); will get received as expected ?
Manifest :
<receiver
android:name="di.k23b.hw3.receivers.BatteryMonitoringReceiver"
android:enabled="false" >
<intent-filter>
<action android:name="#string/intent_action_setup_alarm" />
<action android:name="#string/intent_action_cancel_alarm" />
<action android:name="#string/intent_action_monitor" />
</intent-filter>
</receiver>
I would expect implicit intents to propagate to a registered receiver - why do I have to make those implicit intents explicit ? I expect this to be easy to answer - I just overlooked/didn't quite get something in the docs :)
Do I need to make sure that the call to _enableDisableReceivers(ctx, true); will actually enable the receivers before I broadcast the Intent ? Similarly do I have to wait till the intent is received before I call _enableDisableReceivers(ctx, false); to disable the receivers ? If yes how should I go about that ?
(Bonus off the first answer I got) It is not possible to use LocalBroadcastManager with the AlarmaManager - With a boot receiver ? (I guess no)
For completeness :
private static void _enableDisableReceivers(Context ctx, boolean enable) {
Log.d(_tag, "enable/disable receivers");
for (Class<? extends BaseReceiver> receiver : RECEIVERS)
BaseReceiver.enable(ctx, enable, receiver);
}
where :
public static void enable(Context context, boolean enable,
Class<? extends BaseReceiver> receiver) {
PackageManager pacman = context.getPackageManager();
final ComponentName componentName = new ComponentName(context, receiver);
Log.d(_tag, componentName.toString());
final int state = (enable) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
pacman.setComponentEnabledSetting(componentName, state,
PackageManager.DONT_KILL_APP);
Log.d(_tag,
"pacman :" + pacman.getComponentEnabledSetting(componentName));
}
And for mind boggling completeness (BaseMonitoringReceiver) :
#Override
final public void onReceive(Context context, Intent intent) {
// FIXME : possible NPE below ?
final String action = intent.getAction(); // can intent==null ?
Log.w(TAG, "" + action);
resources = context.getResources();
ac_setup_alarm = resources.getText(R.string.intent_action_setup_alarm);
ac_cancel_alarm = resources
.getText(R.string.intent_action_cancel_alarm);
ac_monitor = resources.getText(R.string.intent_action_monitor);
if (ac_setup_alarm.equals(action) || ac_cancel_alarm.equals(action)) {
monitoringIntent = new Intent(context, this.getClass());
monitoringIntent.setPackage(RECEIVERS_PACKAGE_NAME);// TODO: needed?
final boolean enable = ac_setup_alarm.equals(action);
setupAlarm(context, enable);
} else if (ac_monitor.equals(action)) {
// monitoring - got broadcast from ALARM
Class<? extends WakefulIntentService> serviceClass = getService();
WakefulIntentService.sendWakefulWork(context, serviceClass);
} else {
Log.w(TAG, "Received bogus intent : " + intent);
return;
}
}
Subclasses (like the BatteryMonitoringReceiver in the manifest) just override getService() - neat no ? Notice onReceive is final.
This is not an answer - just wanted to ask questions that won't fit in a comment.
What you are doing - just enabling a receiver for long enough to send it an intent - looks pretty unusual to me. Are you sure that is what you want to do? I'm used to having to enable/disable receivers for system intents, but not for custom intents.
Regarding Q#2, why is there an issue of trying to reduce the window during which the receiver is enabled? Why not enable the receiver before sending the intent, and then don't disable it until after you have received the intent?
I'm assuming that all of this is happening in the same process - it sounds like that is the case. And, if that is the case, why bother declaring your receiver in your manifest at all? You could also consider switching to LocalBroadcastManager.
Edit:
Question 3. As you suspect it is not possible to use LBM with Alarm Manager. See this post.

Checking if a BroadcastReceiver is declared in the manifest in runtime?

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;
}

App Widget stops responding to input after all instances are removed and another added

I am having trouble when I add a one or more instances of my widget to the home screen, remove them all, then add another.
Here is the code I use to set the "onClick" intent for each button (button is a resource)
protected void matchButtonToAction(Context context, RemoteViews views, String action, int button) {
Intent intent = new Intent(context, MightyToggleWidget.class);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
views.setOnClickPendingIntent(button, pendingIntent);
}
This only happens when I remove ALL instances and add one. If I add 2, remove 1 and add 1 it still works.
It is still receiving and reacting to battery events, but not other events (such as wifi state change events)
Any ideas what could be causing this?
Thanks!
I have found the problem. The onEnabled event gets triggered at the start when the first widget is added. The onDisabled event gets triggered when the last widget is removed, but the onEnabled event does not get triggered when you try to add another "first" widget.
I had code that was similar to the examples in those events. This resulted in the packagemanager unregistering my AppWidgetProvider from receiving these events
#Override
public void onEnabled(Context context) {
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(new ComponentName(context.getPackageName(), getClass().getName()), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
#Override
public void onDisabled(Context context) {
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(new ComponentName(context.getPackageName(), getClass().getName()), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
I have added a static method that is called when the Configuration Activity adds a new instance that calls the PackageManager. Here is the code if anyone finds it useful
public static void newInstanceAdded(Context context, AppWidgetManager appWidgetManager, RemoteViews views, SharedPreferences prefs, int id){
ComponentName thisAppWidget = new ComponentName(context, MightyToggleWidget.class);
int ids[] = appWidgetManager.getAppWidgetIds(thisAppWidget);
if (ids.length == 1){
PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(new ComponentName(context.getPackageName(), MightyToggleWidget.class.getName()), PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
updateWidgetInstance(context, appWidgetManager, views, prefs, id);
}
Hope this helps!

Categories

Resources