I am newbie in android programming; sorry if my question is easy :)
I'm trying to write code that monitors the battery level on the phone and if it is, lower some level for example (%15), create a message that asks user to plug the charger. I know that I need to use BroadcastReceiverclass and I want to use it in my MainActivity class. Here is the code I have:
public class MainActivity extends Activity{
BroadcastReceiver br = new BroadcastReceiver() {
#Override
public void onReceive(final Context context, Intent intent) {
String intentAction = intent.getAction();
Log.d("receiver", intentAction);
int level = intent.getIntExtra("level", 0);
if (level < 15){
Log.d("receiver", "battery level low");
}
if (Intent.ACTION_BATTERY_OKAY.equalsIgnoreCase(intentAction)) {
Log.d("receiver", "battery level okay");
}
}
};
......
but it seems that the onReceivemethod is never called since I never see the Log.d("receiver", intentAction) message on Android Studio debug window.
I also have registered br in onResume and unregistered it in onPause:
public void onResume() {
super.onResume();
filter.addAction("receiver");
registerReceiver(br, filter);
}
public void onPause() {
super.onPause();
unregisterReceiver(br);
}
But still I am not getting any message.
Can anybody please help me? Should I also add something to AndroidManifest.xml?
If you dont want to use BroadcastReceiver simply dont use it. Battery intent is sticky intent so you can check it without need of BroadcastReceiver and i also dont think its good idea to put receiver in activity. You can check battery stuff in your activity like this and you dont need to edit your manifest
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, filter);
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level / (float)scale;
if(batteryPct < 15){
//do your stuff
}
Your code in onResume() is wrong. You will have to update it as follows.
filter.addAction(Intent.ACTION_BATTERY_LOW);
filter.addAction(Intent.ACTION_BATTERY_OKAY);
registerReceiver(br, filter);
to include the ACTION_BATTERY_LOW and ACTION_BATTERY_OKAY filters as mentioned in the docs.
Related
Is there any way to create a service that runs forever on a background for Android user to check whether their screen on or off, etc?
I'm about to create an analytics, so I need to know when the user turn on or turn off their screen.
Thanks, I will appreciate all the input
You may use Android broadcast receiver to detect screen on and off.
Here is a good example of it
https://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
you may also follow this thread
https://stackoverflow.com/a/9478013/2784838
You need to create broadcast receiver and manage screen on or off status.
Declare receiver in manifest:
<receiver android:name=".DeviceWakeUpReceiver" />
public class DeviceWakeUpReceiver extends BroadcastReceiver {
private static final String TAG = "DeviceWakeUpService";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "onReceive() called");
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//End service when user phone screen off
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
//Start service when user phone screen on
}
}
}
You cannot use a BroadcastReceiver for receiving screen off/on events.
Write a intent service which is started via boot complete listener and register for Intent.ACTION_SCREEN_OFF and Intent.ACTION_SCREEN_ON.
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(new ScreenOffOnReceiver(), filter);
class ScreenOffOnReiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// Screen OFF
else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// Screen ON
}
}
}
I'm looking for a way of executing a piece of code within my Android application when the phone reaches 10% battery life. Would anyone be able to point me in the right direction of how to do so?
Get battery level in percentage
Intent batteryIntent = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
float levelPert;
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
// Error checking that probably isn't needed but I added just in case.
if(level == -1 || scale == -1) {
levelPert = 50.0f;
}
levelPert = ((float)level / (float)scale) * 100.0f;
P.S. As mentioned in the documentation that BatteryManager is sticky intent, so there is no need to add manifest declaration.
You can read more about getting Battery details here
From developer.android.com :
You can't easily continually monitor the battery state, but you don't need to.
Generally speaking, the impact of constantly monitoring the battery level has a greater impact on the battery than your app's normal behavior, so it's good practice to only monitor significant changes in battery level—specifically when the device enters or exits a low battery state.
From this link
Write one receiver for getting the battery level like this:
public class BatteryReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
if (level < 10) {
// Write your code here
}
}
}
Write One Service:
public class BatteryService extends Service {
private BatteryReceiver receiver;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
receiver = new BatteryReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(receiver, filter);
}
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(receiver);
}
}
Register this service in your Manifest file like this:
<service android:name="com.example.testandroid.BatteryService" >
</service>
then start the service in First Activity is Enough.
I am trying to build an alarm application. When the alarm turns on, the user has to scan a matching QR code before it is turned off. I've taken a look at this link to get the sound playing: How to play ringtone/alarm sound in Android and I am using the ScanningViaIntent from the zxing library for the QR code scanner: https://code.google.com/p/zxing/.
So I start the sound in the onStart() activity:
#Override
public void onStart(){
super.onStart();
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
r = RingtoneManager.getRingtone(getApplicationContext(), notification);
r.play();
}
The user then starts the scanner by pressing a button:
private class HandleClick implements OnClickListener{
public void onClick(View arg0) {
IntentIntegrator integrator = new IntentIntegrator(AlarmRequirementsActivity.this);
integrator.initiateScan();
}
}
The result of the scanner is returned here:
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
IntentResult scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
if (scanResult != null) {
System.out.println("scanREsult" + scanResult);
System.out.println("requestCode: " + requestCode);
TextView result =(TextView)findViewById(R.id.scanResult);
if (resultCode == RESULT_OK) {
String scanResultString = intent.getStringExtra("SCAN_RESULT");
if(scanResultString .equals(matchString))
{
result.setText("You found it!");
r.stop();
}
else
{
result.setText("\"" + scanResultString + "\""+ " did not match");
}
System.out.println(intent.getStringExtra("SCAN_RESULT"));
} else if (resultCode == RESULT_CANCELED) {
}
}
// else continue with any other code you need in the method
}
As you can see, I call r.stop() after a successful match. However these are my problems:
The activity is restarted after coming back from the scanner. It doesn't matter if the match was successful or not.
This results in two alarm tones being played now
I've tried putting it in the onCreate() method but to no avail as well.
UPDATE:
I've tried:
#Override
public void onStart(){
super.onStart();
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
r = RingtoneManager.getRingtone(getApplicationContext(), notification);
if(!r.isPlaying())
{
r.play();
}
}
and this below. Both of which with the same problems
if(scanResultString .equals(matchString))
{
result.setText("You found it!");
if(r.isPlaying())
{
r.stop();
}
}
The activity is restarted after coming back from the scanner. It doesn't matter if the match was successful or not.
I assume that you need to start another activity to do the scan, which means that your activity will (at least) need to be paused and more likely stopped to allow that other activity to run (as per the Android activity lifecycle).
Therefore, you will have to expect onStart() to be called when returning from the scanner.
This results in two alarm tones being played now
You should be able to avoid this and your code to check if the ringtone is already playing seems like a good start. However, I suspect you are creating a new ringtone object each time onStart() is executed.
It is hard for me to guess at all of the things you will need to do to fully resolve your problems (not to mention problems you will only see when your activity is fully recreated by Android - for example when the screen orientation changes - as this needs further handling in your code; see the Android doc for the activity lifecycle, particularly onSaveInstanceState()).
My guess at the next step would be to move the line:
r = RingtoneManager.getRingtone(getApplicationContext(), notification);
into your onCreate() method. My hope is that this, combined with the if (!r.isPlaying()) code should prevent the double-alarm issue in most cases.
Is there anyway to check if onResume was called from the device waking up from sleep state in Android?
The reason why I need to check that is I don't want it to call a particular method if resumed from sleep state:
#Override
public void onResume() {
super.onResume();
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())
&& !SomeCrazyMethodOrPropertyCheckingIfDeviceWakedUpFromSleep) {
processIntent(getIntent());
}
}
You might say "Take that processintent method out of onResume"... It's not an option, NFC P2P mode requires you to process the received NDEF message inside onResume.
I would recommend overriding onNewIntent() to handle the NFC intents:
#Override
public void onNewIntent(final Intent intent) {
setIntent(intent);
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
processIntent(intent);
}
}
In processIntent() you can check whether the intent was handled already:
private void processIntent(final Intent intent) {
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) {
// Log.v(TAG, "Ignoring intent; already treated this intent.");
return;
}
intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
// new intent; process it
...
}
Likely this will solve your problem.
I think you can try to do something with ACTION_SCREEN_ON :
register a receiver for it (you need to it in code, it won't work in manifest).
in the onReceive do something like:
MY_FLAG_JUST_WAKE_UP = true;
and in the onResume() :
if(!MY_FLAG_JUST_WAKE_UP){
doStuff();
}
MY_FLAG_JUST_WAKE_UP = false;
But, it need to be tested, I don't know if you will always receive the intent before the onResume() get called.
So I've got 3 java files :
ServiceActivity - main activity where everything starts ( static int i is defined earlier in this file)
Elserwis - it is the service (it has a timer where I've passed the variable i -> it will be the hour since when the timer must turn on)
Sekundo - the intent where user puts the hour => >variable i<
Here is the fragment of code from main activity -> ServiceActivity:
private OnClickListener startListener = new OnClickListener() {
public void onClick(View v){
Intent intent = new Intent(getApplicationContext(), Sekundo.class);
startActivityForResult(intent,1337);
}
};
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data ) {
/* Place out code to react on Activity-Result here. */
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 1337){
i=data.getIntExtra("result",5);
Toast tost = Toast.makeText(getApplicationContext(), "ELO"+data.getIntExtra("result",0)+data.getIntExtra("result1",0), 1000);
tost.show();
startService(new Intent(SerwisActivity.this,Elserwis.class));
}
}
I think the problem is in the end, where startService lays (as a subfunction of onActivityResult)
If you need any other fragment of code I can paste it here, but the question is:
My app is running very slowly at the beginning when the timer starts, and the Toast shows for over 1 minute. Anyone know why?
EDIT:
public class Elserwis extends Service {
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
okresowePowiadomienie();
Toast.makeText(getApplicationContext(),"Service LAUNCHED!", 1000).show();
}
Date data33 = new Date(111,11,SerwisActivity.i,2,25);
int d = data33.getDate();
Timer timer = new Timer();
public void okresowePowiadomienie(){
TimerTask timerTask = new TimerTask(){
public void run() {
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher,"OKRes",System.currentTimeMillis());
Intent notIntent = new Intent(getApplicationContext(), SerwisActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, notIntent, 0);
notification.setLatestEventInfo(getApplicationContext(),"Powiadomienie x:","Kliknij aby d:usunac ;)t:"+d,contentIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(1335, notification);
// } };
}};
timer.scheduleAtFixedRate(timerTask ,data33 , 120000); }
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
Toast.makeText(this, "Service dead!", Toast.LENGTH_LONG).show();
}
}
thats just alpha version of my code but final will be similar ( now it only passes information about the day to my service -> in final version it should pass hour and minute)
The "Service LAUNCHED!" toast stays on for ages, it crashes most of the time on AVD, on my real smartphone it just takes long but still it should work smoothly...
Basically the problem started when i moved startService from onClick() function TO the onActivityResult. It needs to stay there because service uses the int i (user types types int i in the new intent) to set the data for my timer(timer is in the Elserwis). I've updated my first post with the service code so u can get what i mean
I'm GUESSING that startService itself is not causing any blocking.
I'm GUESSING that you have code in startService that takes awhile to complete and causes your application UI to lock up.
If this is the case, then what you would need to do is create a new thread inside your service before running the code that causes the delay.
You need to keep any long-running blocks of code in a separate thread to not block the UI. I would be interested in the code that is in Elserwis.class because that would help identify where the problem actually lies. Or if you look at your code and figure it out based on what I said, then you need not post any more code.