How to access BatteryManager's BATTERY_PROPERTY_CURRENT_NOW? - android

I'm trying to get the current from the API. There's a function at the bottom of the documentation (https://developer.android.com/reference/android/os/BatteryManager.html) called getIntProperty, so I presume that'd be the function I'd need. However, up to now I've been simply using the getIntExtra function on an ActionBatteryChanged intent, and that same method doesn't work for this. What do I need to do different?

That function is used to get the current value, not get updates like you do with a Broadcast and an Intent. You'd call batteryManager.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW) to get the value. Any of the BATTERY_PROPERTY_X constants could work, but not every phone supports all of them.

A more comprehensive code samples:
Declare this at the class level
private BatteryManager mBatteryManager = null;
onCreate()
{
mBatteryManager = (BatteryManager) getSystemService(Context.BATTERY_SERVICE);
}
Create a timer and inside the timer routine, add this
int mBatteryCurrent = mBatteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CURRENT_NOW);
The current is in uA unit. a positive integer means drawing current out of
battery and a negative integer means charging current into battery.

Related

What's the best way to update LiveData in Android?

I have the two ways to update a LiveData's value.
Fitst
myLiveData.value = myLiveData.value?.apply {
arg1 = value1
arg2 = value2
}
Just update existing value and pass it again.
Second
viewState.value = MyObject(arg1 = value1, arg2 = value2)
Create a new object every time and pass it.
Whisch the way is better in terms of optimisation and code beauty?
P.S. The first term is much more important. Thx in advance.
If you have two values that must be available at the same time, the second approach is the only one that makes sense. With the first approach, the first value will get quickly overwritten by the second. It's entirely possible that an observer could miss the first value. And, an observer that gets attached after the second value is set will only ever see the second value.
The cost of creating a new object every time is not very big. Don't try to optimize that way - it's simply not relevant.

Stop initial triggering if device is already inside Geofence android

I am using Geofencing on android, and when creating a geo-fence the device is getting notified if the user was already inside the geo-fence, which is not the behavior I'm looking for, I only want to notify on transition ENTER and EXIT.
This is how I'm creating the geofence request:
private GeofencingRequest createGeoFenceRequest(List<Geofence> geofenceList) {
return new GeofencingRequest.Builder()
//The INITIAL_TRIGGER_ENTER is used to notify the user initially if he/she/other
//is already inside the geo-fence zone
//.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
.addGeofences(geofenceList)
.build();
}
And inside my GeofenceTransitionService.java:
#Override
protected void onHandleIntent(#Nullable Intent intent) {
if (intent != null) {
geofencingEvent = GeofencingEvent.fromIntent(intent);
// Retrieve the transition type.
geoFenceTransition = geofencingEvent.getGeofenceTransition();
}
}
The transition type is returned as Geofence.GEOFENCE_TRANSITION_ENTER even though I am not entering, I am already inside the geofence.
Anyone know how I can stop this initial trigger ?
Why you got the initial trigger
tl;dr
It's the default behavior
I got here with a similar problem of yours:
The transition type is returned as Geofence.GEOFENCE_TRANSITION_ENTER even though I am not entering, I am already inside the geofence.
After some research, I found this behavior stated on the GeofencingRequest.Builder documentation:
Public Methods
public GeofencingRequest.Builder setInitialTrigger (int initialTrigger)
Sets the geofence notification behavior at the moment when the geofences are added. The default behavior is INITIAL_TRIGGER_ENTER and INITIAL_TRIGGER_DWELL.
To understand what those constants actually mean, we need to check the documentation for the enclosing class, GeofencingRequest:
Constant Summary
int INITIAL_TRIGGER_DWELL
A flag indicating that geofencing service should trigger GEOFENCE_TRANSITION_DWELL notification at the moment when the geofence is added and if the device is already inside that geofence for some time.
int INITIAL_TRIGGER_ENTER
A flag indicating that geofencing service should trigger GEOFENCE_TRANSITION_ENTER notification at the moment when the geofence is added and if the device is already inside that geofence.
int INITIAL_TRIGGER_EXIT
A flag indicating that geofencing service should trigger GEOFENCE_TRANSITION_EXIT notification at the moment when the geofence is added and if the device is already outside that geofence.
This explains why you were notified of a GEOFENCE_TRANSITION_ENTER even though you didn't use setInitialTrigger() - it's the default behavior.
While investigating this, I found out something interesting. If you subscribe to entrances and departures of geofences and then set the initial trigger to INITIAL_TRIGGER_ENTER | INITIAL_TRIGGER_EXIT (bitwise OR; summing both constants together would also work), you will be notified of all the geofences you're currently inside (with GEOFENCE_TRANSITION_ENTER) and also of all the geofences you're currently outside (with GEOFENCE_TRANSITION_EXIT). I haven't thought about a good use case for this, but found it interesting anyway.
How to stop the initial trigger
tl;dr
Set the initial trigger to 0, using a constant to attribute meaning to the number (e.g., private static final int NO_INITIAL_TRIGGER = 0)
Taking a closer look into the documentation of setInitialTrigger() it's possible to read:
Parameters
initialTrigger the notification behavior. It's a bit-wise of INITIAL_TRIGGER_ENTER and/or INITIAL_TRIGGER_EXIT and/or INITIAL_TRIGGER_DWELL.
The hint of using a bitwise operation, combined with the documentation found for those constants (which work as flags for each type of transition) led me to question what would happen if all of the bits were turned off.
So I tried to pass the value of 0 to setInitialTrigger(), in order to override the default behavior and turn off all of the initial triggers without having to resort to the workaround proposed by rfn123:
private GeofencingRequest createGeofencingRequest(List<Geofence> geofences) {
return new GeofencingRequest.Builder()
.setInitialTrigger(0)
.addGeofences(geofences)
.build();
}
Or - perhaps even better - giving some meaning to the magic number:
private static final int NO_INITIAL_TRIGGER = 0;
private GeofencingRequest createGeofencingRequest(List<Geofence> geofences) {
return new GeofencingRequest.Builder()
.setInitialTrigger(NO_INITIAL_TRIGGER)
.addGeofences(geofences)
.build();
}
After some hours of testing this seems to be a sensible approach even if it relies on a poorly documented behavior (as keepTrackOfYourStack has noticed, the documentation has been updated to clarify this).
Please note: From the tests I performed, it's still possible to get an almost instant trigger for a transition, depending on chosen geofences' radii and current location's precision.
For instance, you might be slightly away from the geofence and then suddenly your position is updated, putting you inside the geofence: this will trigger a geofence entrance notification.
However, this entrance notification is not related to the initial trigger you've configured, but to the update in your perceived position.
On a leaving note, if you don't mind, I have a suggestion for an alternate way to implement the onHandleIntent() method.
Instead of checking for the intent object's nullity, just pass that responsibility to the GeofencingEvent#fromIntent() call.
You can then check the validity of the returned event object, using a guard clause - which will increase your method's readability (at least in my opinion).
This will allow you to both test for nullity and check if the event has an error.
Something like this:
#Override
protected void onHandleIntent(#Nullable Intent intent) {
GeofencingEvent event = GeofencingEvent.fromIntent(intent);
if (event == null || event.hasError()) {
logInvalidEvent(event);
return;
}
// Process the event...
}
A workaround might be passing INITIAL_TRIGGER_DWELL to the setInitialTrigger() method.
This will only trigger a notification if the device is already inside the geofence for some time. You can set this time to a very large number.
However this only works if you solely use GEOFENCE_TRANSITION_DWELL in the initial triggering and are otherwise not interested in adding a dwell notification.
Check this link: https://developers.google.com/android/reference/com/google/android/gms/location/GeofencingRequest#INITIAL_TRIGGER_ENTER
it looks like they fixed the documentation and 0 works even though there is no constant
documentation update
From the documentation
initialTrigger the notification behavior.
It's a bit-wise of GeofencingRequest.INITIAL_TRIGGER_ENTER and/or GeofencingRequest.INITIAL_TRIGGER_EXIT and/or GeofencingRequest.INITIAL_TRIGGER_DWELL. When initialTrigger is set to 0 (setInitialTrigger(0)), initial trigger would be disabled.

Screen tracking support - Firebase 9.8

According Firebase Android SDK Release Notes with 9.8 update we have screen tracking support with android screens and activities... The documentation says that this event works like that:
mFirebaseAnalytics.setCurrentScreen(activity,class_name,class_override_name);
In my case, I don't need overrides class name and I send null value... But i'm waiting 48h and my firebase analytics console doesn't show info about this event, any ideas?
Thanks in advance!
Another very important thing that I've noticed only after two days of intensive struggling: the setCurrentScreen method MUST be called on the UI thread.
I was only able to see that after looking for a light in the Firebase decompiled code:
#MainThread
#Keep
public final void setCurrentScreen(#NonNull Activity var1, #Size(min = 1L,max = 36L) #Nullable String var2, #Size(min = 1L,max = 36L) #Nullable String var3) {
//...
}
Whenever this method is called a event of type screen_view is logged.
And keep in mind the Firebase size restrictions. The maximum size of a screen name is 36 characters long.
First I had the same question: where is my event with current screen name on the Firebase dashboard?
I've called method mFirebaseAnalytics.setCurrentScreen(this, "MainActivity", null); with no result.
Thanks to the comment by Benoit I realized that this method indicates the value of implicit parameter that is automatically attached to any event you send.
That means it's not independent event, it's a parameter that will stick to all your events since you set it.
This will be useful if you have changing screens within single Activity. For example when you have multiple fragments with one hosting Activity. And you call this method in each fragment in onResume().
If you want to have distinct metric with the name of your screen - fire explicitly a new event for that.
Bundle params = new Bundle();
params.putString(FirebaseAnalytics.Param.ITEM_CATEGORY, "screen");
params.putString(FirebaseAnalytics.Param.ITEM_NAME, "MainActivity");
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.VIEW_ITEM, params);
val bundle = Bundle()
bundle.putString(FirebaseAnalytics.Param.SCREEN_NAME, "YOUR SCREEN NAME")
mFirebaseAnalytics.logEvent(FirebaseAnalytics.Event.SCREEN_VIEW, bundle)
Also Firebase Analytic's screen tracking is automatic. No need for explicit separate event tracking.
Sets the current screen name, which specifies the current visual context in your app. This helps identify the areas in your app where users spend their time and how they interact with your app.
Note that screen reporting is enabled automatically and records the class name of the current Activity for you without requiring you to call this function. The class name can optionally be overridden by calling this function in the onResume callback of your Activity and specifying the screenClassOverride parameter.
If your app does not use a distinct Activity for each screen, you should call this function and specify a distinct screenName each time a new screen is presented to the user.
The name and classOverride remain in effect until the current Activity changes or a new call to setCurrentScreen is made. I will try to add this method to onResume Method. I do not know the result but i will share my experience.
firebaseAnalytics.setCurrentScreen(activity,screeenName,activity.getClass().getSimpleName());
firebaseAnalytics.setMinimumSessionDuration(100L);
params = new Bundle();
params.putString(FirebaseAnalytics.Param.ITEM_CATEGORY, "screen");
params.putString(FirebaseAnalytics.Param.ITEM_NAME, screeenName);
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.VIEW_ITEM, params);
Try using setCurrentScreen as well as manual event fire as firebase doesn't send data immediately to the console...but if event is fired up..all the remaining data is sent to firebase..
Just call that method in onResume(), and check the tracking through DebugView. it worked for me.
Check out the documentation.

Will someone please explain RESULT_FIRST_USER

I don't understand the meaning, value, or importance of RESULT_FIRST_USER, other than that my own result codes must be greater than 1. Will someone please explain it? RESULT_OK and RESULT_CANCELED make perfect sense to an english speaker. But what in the world of android is RESULT_FIRST_USER? All the documentations says about it is
Start of user-defined activity results.
The answer to the question is actually the combination of comments from #CommonsWare and #Chris. So, for the sake of progeny, I am going to consolidate the comments and make it available in one place.
Basically, there are two predefined constants for the requestCode and they are Activity.RESULT_OK and Activity.RESULT_CANCELLED. However, android developers can also set custom codes for their apps by using the offset Activity.RESULT_FIRST_USER. Doing so ensures that there are no clashes between constants set at the OS level and the app level.
Purely, my opinion, I think that the FIRST USER suffix is meant to refer to developers – just like how end consumer refers to consumers of a said product – who are the first users before the app users.
Below is an example of how you can use this offset,
public static final int MY_RESULT_CODE = Activity.RESULT_FIRST_USER + 1;
When an activity ends, it can call setResult(int) to return data back to its parent.
It must always supply a result code, which can be the standard results
RESULT_CANCELED (Standard activity result: Operation canceled. Constant Value: 0)
RESULT_OK (Standard activity result: operation succeeded. Constant Value: -1), or any custom values starting at RESULT_FIRST_USER (Start of user-defined activity results. Constant Value: 1). In addition, it can optionally return back an Intent containing any additional data it wants.
So, bottom line since you must supply the result code Android "helps' you a bit by saying: please state if the result code of this Activity is OK, CANCELED or you have your own, custom made, result.
When you finish an activity, you can call setResult(RESULT_CODE) to send back data to another activity. If you don't call this method, the default value will be RESULT_CANCELLED (which equals 0)
Example of returning data:
Intent intent= new Intent();
intent.putExtra("data",data);
setResult(YOUR_RESULT_CODE,intent);
finish();
An activity result is a 32-bit integer. The possible values are divided into three ranges:
-2 and below: Unused.
-1 and 0: System-defined values. That is, activity results defined by Android.
1 and above: User-defined values. That is, activity results defined by app developers.
RESULT_FIRST_USER identifies the first value in the user-defined range. The following sample definitions show how system- and user-defined values fit together:
public static final int RESULT_OK = -1; // Defined by Android. You don't write this code.
public static final int RESULT_CANCELED = 0; // Defined by Android. You don't write this code.
public static final int RESULT_ENDED_GAME = RESULT_FIRST_USER + 0; // Defined by an app.
public static final int RESULT_ACTIVATED_RADAR = RESULT_FIRST_USER + 1; // Defined by an app.
public static final int RESULT_LAUNCHED_ROCKETS = RESULT_FIRST_USER + 2; // Defined by an app.

Measure time for rendering ListView

How can I measure time that ListView/ListActivity takes for rendering its list?
I have a ListActivity that takes a long time to show (on older devices it's ~3s) and I'd like to optimize that.
EDIT:
I already have time between Activity1 and Activity2. During this time, Activity2 is doing some stuff (initializing). Among other things, it renders its list. I want to get time this activity takes to render that list. If total time between activities is 3s, I want to know whether rendering list takes 2.9s or 0.5s....
You could simply ouput the time. For example you could use the logcat
final long t0 = System.currentTimeMillis();
// code to measure
Log.w(TAG, "TEXT" + System.currentTimeMillis()-t0);
Of course you could use any other system for the ouput like a dialog or stuff. Just use what you like.
EDIT:
If you don't want to use a debug message in your code all the time you could do it like this:
Create a class called settings:
public class Settings {
public static final boolean DEBUG = true;
// If you prefer you could do use an enum
// enum debugLevel {SHOW_EVERYMESSAGE, ERRORS, IMPORTANT_MESSAGES, ...}
// In your classes you would have to check that DEBUG is less or equal than
// the debugLevel you want
}
In classes where you want to use a debug message simply do this
import xxx.yyy.Settings
class foo {
final static boolean DEBUG = Settings.DEBUG;
if(DEBUG){
// Debug messages
}
}
Now if you want to disable DEBUG messages you could simply set DEBUG = false in your Settings class.
If you want to measure between two activities you could use intents and send t0 with an intent to the other activity to compute the time. Of course you could include this with if(DEBUG){ /* code */ } statements to spare the sending of the intent in the final release. The if statements should not increase the computation of your code too dramatically.
I cannot tell if Java offers a better implementation using System.currentTimeMillis() or System.nanoTime(). Nevertheless, you should give the TimingLogger class a try. Take a look at this article describing the usage of the TimingLogger helper class.

Categories

Resources