Using setComponentEnabledSetting causes the android os to restart upon uninstall. Has anyone else come across this?
ERROR/AndroidRuntime(1143): * FATAL EXCEPTION IN SYSTEM PROCESS: android.server.ServerThread
java.lang.RuntimeException: Error receiving broadcast Intent { act=android.intent.action.PACKAGE_CHANGED dat=package:com.example.foo flg=0x8000010 (has extras) } in com.android.server.NotificationManagerService$2#41b00228
Caused by: java.lang.IllegalArgumentException: Unknown package: com.example.foo
at com.android.server.pm.Settings.getApplicationEnabledSettingLPr(Settings.java:2443)
Here's the code :
public class FooActivity extends Activity {
#Override
protected void onResume() {
super.onResume();
enableReceiver();
}
#Override
protected void onPause() {
super.onPause();
disableReceiver();
}
private void enableReceiver() {
setReceiverState(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
}
private void disableReceiver() {
setReceiverState(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
}
private void setReceiverState(int receiverState) {
getPackageManager().setComponentEnabledSetting(new ComponentName(this, FooBroadcastReceiver.class), receiverState, PackageManager.DONT_KILL_APP);
}
public static class FooBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
}
}
}
the receiver in the manifest :
<receiver android:name="com.example.foo.FooActivity$FooBroadcastReceiver"/>
thanks!
It sounds like you registered a BroadcastReceiver for the android.intent.action.PACKAGE_CHANGED Intent inside your activity, changed its state and then uninstalled the package. The crash does sound like a bug, but I'm guessing while the receiver was still registered the notification manager tried to deliver the uninstall and then crashed.
You might want to call setReceiverState(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); before you uninstall?
I had the same problem, and solved it by not setting the DONT_KILL_APP flag.
getPackageManager().setComponentEnabledSetting(new ComponentName(this,
FooBroadcastReceiver.class), receiverState, 0);
Related
I want the service to start automatically when the phone boots up. But it doesn't run. I also created a foreground service so that the main activity can run in the background.
public void onReceive(Context context, Intent intent) {
if("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())){
Intent tempService = new Intent(context, MainActivity.class);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
context.startForegroundService(tempService);
}else{
context.startService(tempService);
}
}
}
I tried to execute the method in the main activity after executing the class called myService, but I can't do that. You need another way.I tried to execute public void onreceive in the code below, but I couldn't find a way in the end.
private BroadcastReceiver mBatteryInfoReceiver = new BroadcastReceiver() {
#Override
public void onReceive() {
//my code
}
};
I need to do a logout after some time, so I'm opening the login window in my app using.
startActivity(intent);
Problem is that, if the user has my app in the background, my activity will pop up.
Is there a way to easily open an activity but keep my app in the background?
It can be done with Android appliaction component Service.
you can read about it in official documentation by links below.
https://developer.android.com/training/run-background-service/create-service#java
https://developer.android.com/guide/components/services?hl=en
Initialize your Service
public class MyBackgroundService extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
//onCreate - Service created
}
#Override
public void onDestroy() {
//onDestroy - Service destroyed (Stopped)
}
#Override
public void onStart(Intent intent, int startid) {
//onStart - Service started
}
}
Then call Service in your Main Activity
startService(new Intent(this, MyBackgroundService.class));
And don't forget about declare in Manifest.
<service android:enabled="true"
android:name=".MyBackgroundService" />
You can implement "local logout" after some time and when user returns to activity you can detect it. More: https://developer.android.com/guide/components/activities/activity-lifecycle
I've written an android app which checks the network status by using a BroadcastReceiver inherited class:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d("mylog", "NetworkChangeReceiver Hit");
}
}
which is registered in the manifest file like this:
<receiver
android:name="foo.NetworkChangeReceiver"
android:label="NetworkChangeReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.WIFI_STATE_CHANGED" />
</intent-filter>
</receiver>
I needed to handle the internet connection whenever it connects or disconnects. Actually, it works perfectly in normal situations.
But the problem is that when the application is closed manually (by minimizing the app and then closing it by swiping out the app icon in the Recents button menu), it still receives the network status changes. This sometimes causes some exceptions.
Even I have included all the code in receiver function in try/catch block, but still sometimes a toast message containing an error message is shown. This sometimes happen even after some days after the closure of the app.
Please note that the code in the receiver function is more complicated than the code that is shown here and has some access to internal classes and variables.
Your app will still receive events, even if it isn't running. Before you do anything in onReceive(), you can check if the activity is running by:
Option 1: Use a static variable in your activity to check it's state for access from the receiver :
public class YourActivity extends Activity {
public static boolean isRunning = false;
#Overrride
public void onCreate(Bundle savedInstanceState){
isRunning = true;
....
}
//We need receiver to work when app is minimized
/*
#Override
public void onStart() {
super.onStart();
isRunning = true;
}
#Override
public void onStop() {
super.onStop();
isRunning = false;
}
*/
}
And in the receiver:
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.d("mylog", "NetworkChangeReceiver Hit");
if(!YourActivity.isRunning)
return;
}
}
Option 2 : Using the ActivityManager
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (isAppForground(context))
return;
}
public boolean isAppForground(Context mContext) {
ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasks = am.getRunningTasks(1);
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).topActivity;
if (!topActivity.getPackageName().equals(mContext.getPackageName())) {
return false;
}
}
return true;
}
}
You'll need the permission:
<uses-permission android:name="android.permission.GET_TASKS" />
If you define receivers in your manifest, the app will receive events, even if it is not started.
http://developer.android.com/guide/topics/manifest/receiver-element.html
Broadcast receivers enable applications to receive intents that are broadcast by the system or by other applications, even when other components of the application are not running.
To fix this, just don't define the Receiver in the manifest, but do it programatically in onStart and unregister it again in onStop. The problem with this solution is, that you won't get messages if your app is in the background.
private BroadcastReceiver receiver;
#Overrride
public void onStart(){
super.onStart();
IntentFilter filter = new IntentFilter();
filter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
filter.addAction("android.net.wifi.WIFI_STATE_CHANGED");
receiver = new NetworkChangeReceiver();
registerReceiver(receiver, filter);
}
#Override
protected void onStop() {
super.onStop();
//don't forget to unregister the receiver again
unregisterReceiver(receiver);
}
EDIT: onCreate and onDestroy won't work, as onDestroy will not be called in every instance the app is closed (e.g. if it is closed with the task manager)
Solution Found:
I found a perfect solution to my problem. Thanks to the correct answer in Android service crashes after app is swiped out of the recent apps list, I found out that when an app is closed via Recents list, the whole process will be created again and all the static variables will be freshed to their default values, and the onCreate and all other methods will not be called.
So the solution is something like:
public static boolean appStarted = false;
protected void onCreate(Bundle savedInstanceState) {
appStarted = true;
...
}
public class NetworkChangeReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (!MyActivity.appStarted)
return;
...
}
}
The key is to just keep track of when the app starts, and not when the app is closed (because the closing event of app is not dependable and in some situations doesn't work properly)
I am using broadcast receiver in my app to detect incomming call and it works fine. But problem is I can not send action to activity. I mean.. I want do something in activity not in receiver. I read many tutorial but they all are performing action in receiver. Any idea ?
You can declare a BroadcastReceiver as inner class of the Activity. In this case you can directly call activity's methods:
public class MyActivity extends Activity {
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
activityMethod();
}
};
private final IntentFilter filter = new IntentFilter("android.intent.action.PHONE_STATE");
#Override
protected void onStart() {
super.onResume();
registerReceiver(receiver, filter);
}
#Override
protected void onStop() {
super.onPause();
unregisterReceiver(receiver);
}
private void activityMethod() {
}
}
You can start the Activity using an Intent and put a command code in the Intent extra fields. In your Activity you can then decide the behaviour based on the command code or resort to a default behaviour if none is present.
You can start an activity from your receiver via the normal means:
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, YourActivity.class);
startActivity(i);
}
Note though that the user is going to expect that the phone application starts up since they are receiving a phone call. It is very likely a bad idea to hijack the phone call by dumping your own activity on top of the stock dialer app.
I'm using BroadcastReceiver class in android to get information about network change
using the following code:
class NetworkStatus extends BroadcastReceiver{
......
#Override
public void onReceive(Context context, Intent intent) {
}
public void startBroadCastReceiver()
{
}
public void StopBroadCastReceiver()
{
}
I want to stop the broadcast receiver and then start it again
How can I do this
Broadcast receiver likes event handler, Android system calls it automatically when a broadcast matches you defined intent. If you define the boardcast receiver in manifast file, I think the only way you can do it to return immediately when you don't want to handle the broadcast, like the following:
public void onReceive(Context context, Intent intent) {
if (stoppedBroadcast)
return;
// handle broadcast.
}
public void stopBroadcast {
stoppedBroadcast = true;
}
public void resumeBroadcast {
stoppedBroadcast = false;
}
If you want to stop recieving network changes try unregisterReciever in your registering activity/service.
When you want to enable recieving register the reciever with its IntentFilter again.