I'm writing an Android app using old Android phones dedicated to temperature monitoring. Now I'm having problem with an HTC Hero running Android 2.1 update-1. It doesn't receive updates of the battery temperature sensor. It only gets an initial value. It does however receive updates of external power plugged in status. If the external power source is changed a new temperature is received.
Is this behaviour set by the hardware or is it anything I can do about it?
I'm using a BroadcastReceiver:
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryReceiver, filter);
BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(LOG_TAG, "onReceive, action = " + intent.getAction());
float temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 999) / 10f;
boolean externalPower = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
// ...
}
};
This works fine on a Galaxy S4 / Android 4.3.
Like I said, if the external power source is changed (charger is plugged in or unplugged) the receiver is always called, and a new temperature is received.
Re-regestering the receiver doesn't help.
I've tried manually getting the Intent like this in intervals, but the temperature is constant (even if it definitely changed).
handleBatteryIntent(registerReceiver(null, filter));
Seems the temperature is only updated when the external power source status (EXTRA_PLUGGED) has changed.
I've tried two other battery apps, and they have the same problem.
Related
As explained in the following thread:
How to find the devices in the range by using bluetooth?
An android app can get a list of devices in the range (bluetooth enabled)
My question is that if there is any way to limit the discovery range to a certain radius e.g. 1 meter?
Thanks,
Ben
You could use BluetoothDevice.EXTRA_RSSI to get the signal strength.
Nevertheless, it won't be very accurate because it's variable.
private final BroadcastReceiver receiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action)) {
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
System.out.println("RSSI: " + rssi + "dBm");
}
}
};
The value you obtain is in dBm. A really close device would have a rssi between around -20 dBm and -40 dBm depending of the device (built-in Bluetooth device, antenna, actual orientation of device). You can test the values you get to define an average 'dBm-range' for 1 meter. The closer the value is to 0, the stronger the received signal has been.
The problem I'm having is that my count is totally off, from any pedometers, fitbit, or the Samsung Step Counter.
It appears to shut down, and not add any steps after awhile.
If I enter that I'm starting at 3000 for example, it calculates an offset and it stores as a shared preference. It tries to remain registered for the the Sensor. I also store the current steps, so that if the activity that is listening for Step Broadcasts is resumed, it will request for the steps to be output.
I have tried making the service provide notifications and be a foreground service, but the accuracy does not improve, and it uses a ton of power, I have tried a wakelock, with similiar results, not accurate, and uses too much power.
As it stands, my app does not show up in the power usage statistics, so it is hardly using power at all. The hardware sensor should be capturing steps from the accelerometers, and when it does wake up, it should output the newest steps. When it does update, it is closer to the value that I set as the step count.
I am using the Step Counter which was made available in kitkat or above, on some devices. The following code registers for the sensor.
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
if (null != sensor)
{
sensorManager.registerListener(this, sensor,
SensorManager.SENSOR_DELAY_NORMAL);
}
This is within the OnCreate Method of a Service, that I have constructed.
The Service is created as sticky. And uses a broadcast receiver to receive starting steps from an activity, to compute an offset. It also broadcasts the steps that have happened. Here is more of the code.
class MyBroadCastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_REQUEST_STEPS))
{
SendStepBroadcast(currentSteps);
}
else if (intent.getAction().equals(ACTION_SET_STEPS))
{
setSteps = intent.getFloatExtra(
STEPS_OCCURRED, -1);
SendStepBroadcast(setSteps);
}
}
}
#Override
public void onSensorChanged(SensorEvent event) {
if (setSteps > -1) {
offset = setSteps - event.values[0] + 1;
SharedPreferences prefs = getSharedPreferences("com.halfwaythere",
MODE_PRIVATE);
prefs.edit().putFloat("offset", offset).apply();
setSteps = -1;
}
currentSteps = event.values[0] + offset;
SharedPreferences prefs = getSharedPreferences("com.halfwaythere",
MODE_PRIVATE);
prefs.edit().putFloat("currentSteps", currentSteps).apply();
SendStepBroadcast(currentSteps);
}
private void SendStepBroadcast(float steps) {
Intent broadcastSteps = new Intent();
broadcastSteps.setAction(ACTION_STEPS_OCCURRED);
broadcastSteps.putExtra(STEPS_OCCURRED, steps);
this.sendBroadcast(broadcastSteps);
}
In the Activity the following code is used to start the service:
#Override
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, StepService.class);
startService(intent);
}
My most recent set of attempts to fix this, I tried the following:
Use android:process=":background" to start the service in it's own process. I will try this tomorrow in a field test, and see how it works.
I tried setting the count to zero, and found out my code would not allow, so in the above code I used > -1. Since -1 shouldn't be a valid step count.
All of the code above has test wrapped around it, and I've tried to find any edge cases, and have looked over stack overflow for pedometer problems with Step Counter on Samsung Galaxy S4. Or anything about best practices.
Thanks, and if you need any additional info, please let me know.
From my research:
When the screen is locked, the Hardware Sensor waits before outputting steps. It does count steps, but once you press the button on the side it wakes up, and it receives a SensorEvent.
Service was occasionally having Start Command being called. Was very important that I only register once, so I added a boolean that would be flipped once the initialization was called, and flip off after that. Service was paused, but not killed, and Start Command would run upon it being awoken.
Setting Service to Foreground, seems to be getting closer to the value from other pedometers. Uses more battery, but is keeping it going more, so that makes sense.
Did not require wakelock, it was only on for several milliseconds, but that did not cause the hardware sensor to send results.
Will have my Service run till goal is achieved, or offer the option to stop tracking at half way point. I really just wanted something to tell me that I would get my goal if I turned around, anything else will be equivalent to extra steps.
So I will apply what I found and continue on with my app, should be on the App Store by mid July.
I am currently trying to make a reliable way to determine a specific charger type, in my case a music dock like this. The problem is that this dock unfortunately does not send a dock event when docked.
Since I am making an app relying on being able to determine when the device has been docked or undocked. I therefore need a way to filter out and separate these events:
Device is charging through the USB connector(no separate charger)
Device is not connected to a computer
Some sort of way to separate the slow charging dock from a standard charger
I have noticed that my device (LG optimus 4x HD) manages to react differently for every one of these actions. When it is connected to a standard charger it gives no notification message, when it is connected to a computer it tells me USB mode has been activated, and when it is connected to the dock it gives me a slow charger warning.
I need to make a system with the same ability to separate these actions and react to them. Until now I have only made a simple BroadcastReceiver that reacts if the device is connected or unconnected to a charger. I have also managed to monitor the charging state using the code found in the documentation.
Is there any way of determine this specific charger input?
Whenever the device is docked or undocked, the ACTION_DOCK_EVENT action is broadcast. To monitor changes in the device's dock-state, simply register a broadcast receiver in your application manifest as shown in the snippet below:
<action android:name="android.intent.action.ACTION_DOCK_EVENT"/>
If a device is docked, it can be docked in any one of four different type of dock:
Car
Desk
Low-End (Analog) Desk
High-End (Digital) Desk
The dock-state details are included as an extra in a sticky broadcast of the ACTION_DOCK_EVENT action. Because it's sticky, you don't need to register a BroadcastReceiver. You can simply call registerReceiver() passing in null as the broadcast receiver as shown in the next snippet.
IntentFilter ifilter = new IntentFilter(Intent.ACTION_DOCK_EVENT);
Intent dockStatus = context.registerReceiver(null, ifilter);
You can extract the current docking status from the EXTRA_DOCK_STATE extra:
int dockState = battery.getIntExtra(EXTRA_DOCK_STATE, -1);
boolean isDocked = dockState != Intent.EXTRA_DOCK_STATE_UNDOCKED;
You can find the dock state by
boolean isCar = dockState == EXTRA_DOCK_STATE_CAR;
boolean isDesk = dockState == EXTRA_DOCK_STATE_DESK ||
dockState == EXTRA_DOCK_STATE_LE_DESK ||
dockState == EXTRA_DOCK_STATE_HE_DESK;
EDIT :
If your app still not receiving the broadcast try this code to sent manual broadcast and check the code :
adb shell am broadcast -a android.intent.action.POWER_CONNECTED -n com.jm.monitoringbatterydemo/.PowerConnectionReceiver
Change the name of the broadcast and your receiver.
What you can do to solve this problem is look at the % of battery left on your phone. You can then determine that the value is going up, which means it is docked. Only problem with this could be that if you sometimes charge it on a regular charger rather than a dock, you'd still have it respond as if it were one.
More info on reading battery level etc: http://developer.android.com/training/monitoring-device-state/battery-monitoring.html
Would it be helpful to identify the power source using
int BATTERY_PLUGGED_AC Power source is an AC charger.
int BATTERY_PLUGGED_USB Power source is a USB port.
int BATTERY_PLUGGED_WIRELESS Power source is wireless.
from BatteryManager?
Hope this code helps:
IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = mContext.registerReceiver(null, ifilter);
// Are we charging / charged?
int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING ||
status == BatteryManager.BATTERY_STATUS_FULL;
// How are we charging?
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargePlug == 2;
boolean acCharge = chargePlug == 1;
int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float batteryPct = level / (float)scale;
My goal is : when I call some function, I want to get the exact current battery status(level,voltage and etc..).
First I tried to do it in my application as shown on the website. Then I have found actually the ACTION_BATTERY_CHANGED broadcast is sticky which means what I got is from last broadcast, not the exact current value.
Actually, I have looked into the android source code. For the battery interface, the driver has functions to read the registers inside the battery which contain the current soc(state of charge), voltage and etc..
So I am just wondering how and when the system sends the sticky broadcast ACTION_BATTERY_CHANGED? Does it send it periodically(e.g.,every 10 seconds it will read the registers in battery and send the broadcast)? Or does it send based on other criteria(e.g, change of soc, voltage? But voltage will change so frequently in terms of mV)?
To realize my goal, one troublesome way is to implement a system call to call the driver functions and then recompile the NDK to make it usable in my application code. But I just want to know whether I can do this directly through the ACTION_BATTERY_CHANGED broadcast considering what I have mentioned above? Does registering the broadcast again have any effect?
Simply register the Broadcast receiver for the battery level. You will get the result of battery level in onReceive.
private void batteryLevel() {
BroadcastReceiver batteryLevelReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(this);
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
int level = -1;
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
batterLevel.setText("Battery Level Remaining: " + level + "%");
}
};
IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(batteryLevelReceiver, batteryLevelFilter);
}
Hope this will help you.
To elaborate on the answer from Arpit, ACTION_BATTERY_CHANGED is a "sticky" event - which means it doesn't need a receiver to be able to read its values. That way you may call registerReceiver() with receiver equal to null, and read all the battery stats synchronously right away, and there's no need to unregister.
Here's the code:
private void batteryLevel() {
IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent intent = registerReceiver(null, batteryLevelFilter);
if (intent != null) {
int rawlevel = intent.getIntExtra("level", -1);
int scale = intent.getIntExtra("scale", -1);
int level = -1;
if (rawlevel >= 0 && scale > 0) {
level = (rawlevel * 100) / scale;
}
batteryLevel.setText("Battery Level Remaining: " + level + "%");
}
}
Also, in some rare cases, registerReceiver() may throw an IllegalArgumentException: regist too many Broadcast Receivers exception, so you may want to catch it to avoid crashing.
In response to the of the question:
Does it send it periodically(e.g.,every 10 seconds it will read the
registers in battery and send the broadcast)? Or does it send based on
other criteria(e.g, change of soc, voltage? But voltage will change so
frequently in terms of mV)?
There is no single correct answer, Android makes no guarantees and it varies by device.
Based on my experience working with different board bring-ups it is highly dependant on the linux kernel drivers managing power. I've seen it firing uevents off once per second or once every 30 seconds. Even the same device will fire it differently based on whether it is attached to a power source or not. I tend to see that usually there is some fixed timer that triggers it and additionally major events such as attaching/detaching a charger will trigger it as well.
Also see: ACTION_BATTERY_CHANGED firing like crazy
I am writing an application that relies on the Android device (for my current testing purposes an HTC Evo 4G and several original Motorola Droids) being discoverable via bluetooth for 300 seconds.
I am targeting Android version 2.0.1, so according to the API I should be able to prompt the user to enable discoverability for a maximum of 300 seconds. On both my Droids and my Evo the prompt window has 300 seconds listed, but they both end after 120 seconds.
The code I used to prompt the user is here:
private void makeDiscoverable() {
Intent discoverableIntent = new Intent(
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
I am certain that this code runs. However, I later have a handler for when my discoverability status changes (in this case ends, I assume) that reads like this:
if (isDiscoverableChange(action)) {
int discoverState = intent.getIntExtra(
BluetoothAdapter.EXTRA_SCAN_MODE, Short.MIN_VALUE);
if (isDiscoverableState(discoverState)) {
setItOrder();
setUpScanAndDisplay();
} else {
discoverScheduler.cancel();
itScheduler.cancel();
}
}
private boolean isDiscoverableChange(String action) {
return BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action);
}
private boolean isDiscoverableState(int state) {
return state == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE;
}
I tried commenting out the portion that runs when discoverability mode ends, just in case it was cancelling everything prematurely, but discoverability really does end after 120 seconds.
Is this a hardware issue, or am I doing something wrong here?
It appears to be a bug:
Issue 15486: Bluetooth Adapter.EXTRA DISCOVERABLE not obeyed
http://code.google.com/p/android/issues/detail?id=15486
Issue 13361: BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION intent Extra does not extend 120 sec discovery interval
http://code.google.com/p/android/issues/detail?id=13361
First reported Dec 22, 2010, still listed as 'new' status, so I wouldn't expect this to be fixed.
There is bluetooth DiscoverableTimeout value besides Android timeout.
Usually, DiscoverableTimeout is set in file /system/etc/bluetooth/main.conf to 120 .
You should write
DiscoverableTimeout = 0
in /system/etc/bluetooth/main.conf to disable bluetooth timeout. This will allow you to extend Android timeout over than 120 sec.