I am writing an app that when battery reach some level the wifi will automatically shut done, my app works fine while screen is on, but it not do anything when the screnn is lock.
My app is like, start activity, user click the button to start the Service, the service will register the broadcastreceiveer to get the current level of battery, and braodcastreceiver will see if battery level reach the limit and decide to shut done wifi or not
I have try use isScreenOn() to find whether screen is on or off, but this also not work
here is my code
public class BatteryMonitor extends Service {
/*declear variables*/
private BroadcastReceiver batteryReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent){
/* get battery level*/
//Check is screen is on or not
boolean isScreenOn = powermanager.isScreenOn();
//set as 90 just for test function//
if(batteryLevel<=90){
if(isScreenOn==true){
if(isCharging == true && wifimanager.isWifiEnabled()){
//not do anything
}else if(isCharging == false && wifimanager.isWifiEnabled()){
wifimanager.setWifiEnabled(false);
}
}else{
if(isCharging == true && wifimanager.isWifiEnabled()){
//not do anything
}else if(isCharging == false && wifimanager.isWifiEnabled()){
wifimanager.setWifiEnabled(false);
}
}
}
}
};
public void onStart(Intent intent, int startId) {
wifimanager = (WifiManager)this.getSystemService(Context.WIFI_SERVICE);
powermanager = (PowerManager) getSystemService(Context.POWER_SERVICE);
registerReceiver(batteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
};
#Override
public IBinder onBind(Intent i) {
// TODO Auto-generated method stub
return null;
}
}
Create a Separate class for Receiver, register it into Manifest file for Battery change action. Then it will work even when screen is off.
Broadcast Receiver
read this link.
You need to sendBroadcast when you want to send a message to Receiver, make sure that you added proper Action String , in manifest for Receiver ,
Related
Can I keep Android activity alive in background, until user doesn't kill or close the application.
I want to detect user clicks in background some specific hardware button clicks, as onKeyDown is not available in service, I need to keep my activity alive in background until user kills the app.
Does android allows such behavior ?
Update :
I was able to solve this using following approach :
1] Use foreground service,
Ref : https://developer.android.com/guide/components/services.html#Foreground
2] To handle media button click use below approach after Android 21 + ( Use this code in onCreate() of your foreground service ) :
mediaSession = new MediaSessionCompat(this, TAG);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
mediaSession.setCallback(new MediaSessionCompat.Callback() {
#Override
public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
if (mediaButtonEvent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
KeyEvent event = (KeyEvent) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (KeyEvent.KEYCODE_HEADSETHOOK == event.getKeyCode() && event.getAction() == KeyEvent.ACTION_DOWN) {
Log.e(TAG, "Media Button clicked");
handleHeadphoneClick();
}
}
return false;
}
});
mediaSession.setActive(true);
Ref : https://developer.android.com/guide/topics/media-apps/mediabuttons.html
Right from developer.android.com
A service is a component that runs in the background to perform
long-running operations or to perform work for remote processes. A
service does not provide a user interface. For example, a service
might play music in the background while the user is in a different
application, or it might fetch data over the network without blocking
user interaction with an activity. Another component, such as an
activity, can start the service and let it run or bind to it in order
to interact with it. A service is implemented as a subclass of Service
and you can learn more about it in the Services developer guide.
So, as long as you create a service, and the user exits your app it will still run. Just like the example above.
This should give you all the information you need:
Visit this link
Simply, just create a new service class. Here, using this class you are able to see the Hardware button click event in log. Here i am using volume key as a onKeyEvent.
public class Xtra extends Service {
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
final BroadcastReceiver vReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
boolean isScreenOn = powerManager.isScreenOn();
if (!isScreenOn) {
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourService");
mWakeLock.acquire();
// The screen has been locked
// do stuff...
Log.e("Do what you want to do from this service...", "Here screen is off..which do not show or work anything due to screen is off");
Toast.makeText(getActivity(), "Here screen is off..which do not show or work anything due to screen is off", Toast.LENGTH_SHORT).show();
} else {
Log.e("Do what you want to do from this service...", "Here screen is on, works...");
Toast.makeText(getActivity(), "Here screen is on, works...", Toast.LENGTH_SHORT).show();
}
}
};
registerReceiver(vReceiver, new IntentFilter("android.media.VOLUME_CHANGED_ACTION"));
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stub
return super.onStartCommand(intent, flags, startId);
//43200000 schedules notification on every 12 hours
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
Log.e("BgService", "::>> Service Stopped...");
super.onDestroy();
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Make a button click event from your activity to start the service. It will starts your service in background.
Button btnSave;
btnSave.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//From here service starts when you click on a button.
startService(new Intent(activity, Xtra.class));
}
});
Don't forgot to add this service to your manifest.
<service android:name=".Xtra">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
When you click on btnSave, it will starts your service. Now just move to home screen and click the volume key, you will surely get the result as it works fine for me.
Update :
I was able to solve this using following approach :
1] Use foreground service,
Ref : https://developer.android.com/guide/components/services.html#Foreground
2] To handle media button click use below approach after Android 21 + ( Use this code in onCreate() of your foreground service ) :
mediaSession = new MediaSessionCompat(this, TAG);
mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS);
mediaSession.setCallback(new MediaSessionCompat.Callback() {
#Override
public boolean onMediaButtonEvent(Intent mediaButtonEvent) {
if (mediaButtonEvent.getAction().equals(Intent.ACTION_MEDIA_BUTTON)) {
KeyEvent event = (KeyEvent) mediaButtonEvent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (KeyEvent.KEYCODE_HEADSETHOOK == event.getKeyCode() && event.getAction() == KeyEvent.ACTION_DOWN) {
Log.e(TAG, "Media Button clicked");
handleHeadphoneClick();
}
}
return false;
}
});
mediaSession.setActive(true);
Ref : https://developer.android.com/guide/topics/media-apps/mediabuttons.html
I have written the following code for detecting the network status from within the BroadcastReceiver. I start a service when the network is available and stop the service when the network is not available.
I have the following class level variable.
private boolean IsNetworkAlreadyConnected = false;
Within onCreate method of the main class I start the service if the internet is available.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (InternetConnectivity.isConnected(MainActivity.this)) {
IsNetworkAlreadyConnected = true;
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
startService(timerIntent);
}
}
and below is the code for my BroadcastReceiver in the same class,
public class mConnectivityCheckReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals("android.net.conn.CONNECTIVITY_CHANGE")) {
try {
boolean networkAvailable = InternetConnectivity.isConnected(context);
if (networkAvailable) {
if (!IsNetworkAlreadyConnected) {
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
startService(timerIntent);
IsNetworkAlreadyConnected = true;
}
else {
Log.d("KC_HomeActivity", "Network was already connected. No need to start service again.");
}
}
else {
Log.d("KC_HomeActivity", "Network Disconnected. Service Stopped.");
IsNetworkAlreadyConnected = false;
Intent timerIntent = new Intent(getBaseContext(), InActivityTimer.class);
stopService(timerIntent);
}
}
catch (Exception e) {
}
}
}
};
When both Mobile data and Wifi are turned on then the service is started from onCreate method and it is not started again in the BroadcastReceiver but when I turn off the Wifi the Android changes the network mode to Mobile Data but for few seconds there is no internet connectivity and the service is stopped and then started again. I don't want to do this. If there is no connectivity only then the service should be stopped. If the network is shifting from Wifi to Mobile Data then the service should not be stopped.
Note: To check the internet connectivity I am using,
NetworkInfo info = InternetConnectivity.getNetworkInfo(context);
return (info != null && info.isConnectedOrConnecting());
Network connections aren't that precise. You should make it relax a bit, or you'll pull your hair out.
I would implement a smoothing function from the broadcasts. When you get a connectivity change notification, set a timeout for like 15 seconds. At that time, check your status and either start, stop, or do nothing. If another broadcast comes in, clear the first and reset for another 15 seconds. That will give the device time to reconnect.
Well, I want to check the version of a site (this part I know how) every 6h or so.
So, I was thinking about making a service for this and use AlarmManager for it.
Since I need Internet to check the version of the site, I need something to see if the internet is on or to see when it's turned on. After the time passed I'll
So my questions (yep, not just one!) are:
Does AlarmManager works even if the display goes to sleep? When the device wakes up it knows how many time as passed and if passed more that 6h it executes the task?
How to check when internet is available?
How to know when internet is turned on? (some kind of broadcast?)
Is this a good solution?
Alarm Manager:
The alarm manager does not have anything to do with the display state, so Yes it can work even if the screen is off.
Network Avaiability snippet:
public boolean isNetworkAvailable() {
Context context = getApplicationContext();
ConnectivityManager connectivity = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
boitealerte(this.getString(R.string.alert),"getSystemService rend null");
} else {
NetworkInfo[] info = connectivity.getAllNetworkInfo();
if (info != null) {
for (int i = 0; i < info.length; i++) {
if (info[i].getState() == NetworkInfo.State.CONNECTED) {
return true;
}
}
}
}
return false;
}
This function will return true if the network is available, false if it is not (airplane mode, out of reach, etc.)
Don't forget to add permission in your manifest
A possible solution
Have broadcast receiver for the screen off & screen on events like below,
public class ScreenReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// do whatever you need to do here
wasScreenOn = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// and do whatever you need to do here
wasScreenOn = true;
}
}
}
In this receiver give the logic for requesting if network is available..
About the alarm manager. Here is a possible code:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis() + 10000, 6*60*60*1000, pendingIntent);
The first parameter influence how device behave:
RTC - alarm does not wake the device up; if it goes off while the device is asleep, it will not be delivered until the next time the device wakes up
RTC_WAKEUP - wake up the device when it goes off
Does anyone know of a way to obtain the phone service state (IN_SERVICE, OUT_OF_SERVICE, EMERGENCY_ONLY, POWER_OFF) in android.
I was hoping there would be a broadcastreciever to identify the changes, but I can't find anything. I know there's a listener but I'm not sure how I would use that from my app as it runs as a service using a WakefulIntentService (by thecommonsguy).
With something like battery level (ie BATTERY_LOW, BATTERY_OKAY) it's quite easy, but I just can't work out a similar things for phone service changes.
Register a receiver for
public static final String ACTION_SERVICE_STATE_CHANGED = "android.intent.action.SERVICE_STATE";
When you get intent on your receiver just use below little hack from android source
public void onReceive(Context context, Intent intent) {
int state = intent.getExtras().getInt("state");
if(state == ServiceState.STATE_IN_SERVICE)
{
//Do whatever you want
}
}
check source of service state class
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/1.5_r4/android/telephony/ServiceState.java#ServiceState.setFromNotifierBundle%28android.os.Bundle%29
You could write your own BroadcastReceiver. Your receiver will receive connectivity changes and inform your desired instance about the change (for example your own CommunicationManager):
public class ConnectivityReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i(getClass().getName(), "A change in network connectivity has occurred. Notifying communication manager for further action.");
NetworkInfo info = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if(info != null) {
Log.v(getClass().getName(), "Reported connectivity status is " + info.getState() + ".");
}
CommunicationManager.updateConnectivityState(); // Notify connection manager
}
}
For example here your CommunicationManager instance, which will be notified about connectivity changes:
protected static void updateConnectivityState()
{
boolean isConnected = false;
if (_connec != null && (_connec.getNetworkInfo(1).getState() == NetworkInfo.State.CONNECTED) ||(_connec.getNetworkInfo(0).getState() == NetworkInfo.State.CONNECTED)){
isConnected = true;
Log.i(CommunicationManager.class.getName(), "Device is connected to the network. Online mode is available.");
}else if (_connec.getNetworkInfo(0).getState() == NetworkInfo.State.DISCONNECTED || _connec.getNetworkInfo(1).getState() == NetworkInfo.State.DISCONNECTED ) {
isConnected = false;
Log.w(CommunicationManager.class.getName(), "Device is NOT connected to the network. Offline mode.");
}
_isConnected = isConnected;
}
Check the NetworkInfo class for further details about connectivity availability.
Don't forget to register the ACCESS_NETWORK_STATE permisson in your manifest:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
I hope this helps. Regards
In Android 2.2 (Level 7) the function PowerManager.IsScreenOn() returns a boolean that is true if the screen is turned on and false if the screen is turned off. I am developing code for Android 1.5 (Level 3). How do I accomplish the same task in older versions of Android?
I do not want to turn the screen on or off in my code. I just want to know what it is.
There's a better way than using BroadcastReceivers:
// If you use API20 or more:
DisplayManager dm = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays()) {
if (display.getState() != Display.STATE_OFF) {
return true;
}
}
return false;
// If you use less than API20:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
if (powerManager.isScreenOn()){ return true; }
Note that Display.getState() can also return STATE_DOZE and STATE_DOZE_SUSPEND which means that the screen is on in an special way. More info on Display.getState() and his return values here: http://developer.android.com/reference/android/view/Display.html#getState()
Also note that although official documentation recommends using isInteractive() instead of isScreenOn(), if you really want to know the status of the screen, Display.getState() is a better option because of the 'special' conditions that sets the screen on while the device is not interactive.
This is how you should do it:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
boolean result= VERSION.SDK_INT>=VERSION_CODES.KITKAT_WATCH&&powerManager.isInteractive()||VERSION.SDK_INT<VERSION_CODES.KITKAT_WATCH&&powerManager.isScreenOn();
return result;
I'm using the following function:
public boolean isInteractive() {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH
? powerManager.isInteractive()
: powerManager.isScreenOn();
}
You can accomplish this by setting up broadcast receivers for ACTION_SCREEN_ON and ACTION_SCREEN_OFF.
I'm posting this because on a HUAWAI Prism II Android 4.1.1 (API 16) device the game I'm working on had the following annoying behavior:
I'm displaying my main menu which has some animation in a SurfaceView and plays a sound once in a while.
The device goes idle, dims, and then goes dark.
It calls onDestroy on my Activity, and then while the screen is off creates my Activity again, calling onCreate!
So the problem is my animations and sounds are playing while the screen is off. What I really want to happen is for my animation loop to not run at all if the screen is off. Broadcast receivers don't work because I can't store the state from the last time the screen went off. I thought about some hacks involving static booleans but it just seemed like a kluge that may not work and have horrible edge cases. The screen is already off when my Activity is created again, so I won't get an event through the broadcast receiver that my screen is off.
I solved this using both a broadcast receiver and the code listed above.
In my onCreate, I create the broadcast receiver. This will control my animation loop when the screen turns on and off.
if (mScreenReceiver == null) {
mScreenIntentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
mScreenIntentFilter.addAction(Intent.ACTION_SCREEN_OFF);
mScreenReceiver = new ScreenReceiver();
registerReceiver(mScreenReceiver, mScreenIntentFilter);
}
public class ScreenReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
controlAnimLoop(false, false, true);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
controlAnimLoop(false, false, false);
}
}
}
In my controlAnimLoop, I check isScreenOn, which is this code:
private boolean isScreenOn() {
if (android.os.Build.VERSION.SDK_INT >= 20) {
// I'm counting
// STATE_DOZE, STATE_OFF, STATE_DOZE_SUSPENDED
// all as "OFF"
DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
for (Display display : dm.getDisplays ()) {
if (display.getState () == Display.STATE_ON ||
display.getState () == Display.STATE_UNKNOWN) {
return true;
}
}
return false;
}
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
return powerManager.isScreenOn();
}
MainActivity.Java
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_HEADSET_PLUG);
filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(new MyReceiver(), filter);
}
}
MyReciever.Java
public class MyReceiver extends BroadcastReceiver {
MainActivity mActivity;
#Override
public void onReceive(Context arg0, Intent arg1) {
mActivity = (MainActivity) arg0;
TextView tv = (TextView)mActivity.findViewById(R.id.textView1);
if(arg1.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
tv.setText("Headset Plugin ");
} else if(arg1.getAction().equals(Intent.ACTION_POWER_CONNECTED)) {
tv.setText("Power Connected ");
} else if(arg1.getAction().equals(Intent.ACTION_POWER_DISCONNECTED)) {
tv.setText("Power Disconnected ");
} else if(arg1.getAction().equals(Intent.ACTION_SCREEN_ON)) {
tv.setText("Screen ON ");
} else if(arg1.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
tv.setText("Screen OFF ");
}
}
}