I tried to get the app usage from previous day 0 o'clock to today 0 o'clock.
Here is my Code:
val midnight = LocalTime.MIDNIGHT
val today = LocalDate.now()
val todayMidnight = LocalDateTime.of(today, midnight)
val todayMidnightMillis = toMillis(todayMidnight)
val yesterdayMidnightMillis = toMillis(todayMidnight.minusDays(1))
val usageStatsManager = context.getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val queryUsageStatsMap = usageStatsManager.queryAndAggregateUsageStats(yesterdayMidnightMillis, todayMidnightMillis)
val appInfoMap = getNonSystemAppsList()
for (packageName in appInfoMap) {
val usageStats = queryUsageStatsMap.get(packageName.key)
if (usageStats != null) {
if (usageStats.totalTimeVisible > 0) {
val name = usageStats.packageName
val hours = TimeUnit.MILLISECONDS.toHours(usageStats.totalTimeVisible) % 24
val minutes = TimeUnit.MILLISECONDS.toMinutes(usageStats.totalTimeVisible) % 60
val seconds = TimeUnit.MILLISECONDS.toSeconds(usageStats.totalTimeVisible) % 60
//insert into database
}
}
}
private fun toMillis(dateTime: LocalDateTime): Long {
return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
}
For example:
yesterdayMidnightMillis = 1673996400000 (18.01.2023-00:00)
todayMidnightMillis = 1674082800000 (19.01.2023-00:00)
For example, when I call this method(19.01.2023-15:00), the method gives me an app usage of 10 min. If I wait a minute and call the method again, the method gives me an app usage of 11 min.
Since I am not in the specified time interval during this time, the app usage must not increase.
Related
I'm trying to make a string format that, when a user post is uploaded, it expresses the upload time as "~ minutes ago" or "~ hours ago" and so on.
My application works in the way like below
upload post in PostActivity > firebase saves the data of the post (the post is consist of postId, writerId, message, writeTime, bgUri for image, commentCount) > MainActivity gets data from firebase and shows the post on RecycleView by MyAdapter.kt
Below is the PostActivity.kt
class PostActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_post)
supportActionBar?.title = "New Post"
val layoutManager = LinearLayoutManager(this#PostActivity)
layoutManager.orientation = LinearLayoutManager.HORIZONTAL
recyclerView2.layoutManager=layoutManager
recyclerView2.adapter = MyAdapter()
postButton.setOnClickListener {
val newRef = FirebaseDatabase.getInstance().getReference("Posts").push()
post.writeTime= DateTime().toString()
newRef.setValue(post)
finish()
}
}
The writeTime field of post is DateTime().toString().
For the string format, I made a function getdiffTimeText() at MyAdapter.kt which is below.
class MyAdapter(private val posts : MutableList<Post>) : RecyclerView.Adapter<MyAdapter.MyViewHolder>() { //line 20
override fun onBindViewHolder(holder: MyAdapter.MyViewHolder, position: Int) {
val post = posts[position]
holder.timeTextView.text = getDiffTimeText(post.writeTime) //line 32
}
public class MyViewHolder(itemView : View) :
val timeTextView = itemView?.findViewById<TextView>(R.id.timeTextView) //line 51
}
}
fun getDiffTimeText(targetTime: String): String {
val curDateTime = DateTime()
val targetDateTime = DateTime(targetTime)
val diffDay = Days.daysBetween(curDateTime, targetDateTime).days
val diffHours = Hours.hoursBetween(targetDateTime, curDateTime).hours
val diffMinutes = Minutes.minutesBetween(targetDateTime, curDateTime).minutes
if (diffDay == 0) {
if (diffDay == 0 && diffMinutes == 0) {
return "just before"
}
return if (diffHours > 0) {
"" + diffHours + "hours ago"
} else "" + diffMinutes + "minutes ago"
} else {
val format = SimpleDateFormat("yyyy.MM.dd")
return format.format(Date(targetTime))
}
}
Below is the MainActivity
class MainActivity : AppCompatActivity() {
val posts: MutableList<Post> = mutableListOf()
private lateinit var dbref: DatabaseReference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
getUserData()
}
private fun getUserData() {
dbref = FirebaseDatabase.getInstance().getReference("/Posts")
dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (userSnapshot in snapshot.children) {
val post = userSnapshot.getValue(Post::class.java)
posts.add(post!!)
}
recyclerView_main.adapter = MyAdapter(posts)
}
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(this#MainActivity,"failed",Toast.LENGTH_SHORT).show()
}
})
}
}
Below is Post.kt the class of user's post.
class Post {
var postId = ""
var writerId = ""
var message = ""
var writeTime = ""
var bgUri = ""
var commentCount = ""
}
When I run the code, app crashes with the error below.
java.lang.IllegalArgumentException: Invalid format: "1661861458" is malformed at "8"
at org.joda.time.DateTime.<init>(DateTime.java:257)
at <<package name>>.MyAdapterKt.getDiffTimeText(MyAdapter.kt:51)
at <<package name>>.MyAdapter.onBindViewHolder(MyAdapter.kt:32)
at <<package name>>.MyAdapter.onBindViewHolder(MyAdapter.kt:20)
To test the fuction getDiffTimeText() I tried the code below in different activity.
val testTime = DateTime().toString()
val testText = findViewById<TextView>(R.id.testing)
val testText2 = findViewById<TextView>(R.id.testing2)
testText.text = testTime
testText2.text = getDiffTimeText(testTime)
The testTime is String type just like the Post.kt where the type of writeTime field is String.
As the result, textview testText shows 2022-08-31T05:37:55.778Z which is the current time, and testText2 shows just ago.
So it seems the function getDiffTimeText works in this way. But It doesn't work in holder.timeTextView.text = getDiffTimeText(post.writeTime) which is MyAdapter.kt line 32, and the app crashes.
How should I solve this?
*edited my question for clearence, codes that are less relevant are excluded.
Seem the timestamp you passed in line 32 holder.timeTextView.text = getDiffTimeText(post.writeTime) is counting with second instead of millis.
You can try to changed your remote time to millis or just do like that:
val timeInMillis = post.writeTime.toLong() * 1000L // maybe toLongOrNull() for safe usage.
holder.timeTextView.text = getDiffTimeText(timeInMillis.toString())
I used this approach to fix my issue: Though in my case I was just calculating the time and not date. But you can have some idea.
So I was trying to store the time in milliseconds and then retrieving it back to show in a desired format:
Here are the steps I followed:
First saving the time in database
Getting the time from Time Picker :
val h = picker.hour
val m = picker.minute
Converting the total time to milliseconds
val hour = TimeUnit.HOURS.toMillis(h.toLong())
val minute = TimeUnit.MINUTES.toMillis(m.toLong())
val totalTime = hour + minute
Saving the time as a string. (in my case it was Room DB, you can do on Firebase)
Now retrieving the time from database
Initially converted the entered time back to Long from String
val timeMilliseconds = totalTime.toLong()
Converting the milliseconds to hours, minutes and seconds with help of function
val startTime = formatToDigitalClock(timeMilliseconds)
The function
//Converting received long time to proper digital format
private fun formatToDigitalClock(milliseconds: Long): String {
val hours = TimeUnit.MILLISECONDS.toHours(milliseconds).toInt() % 24
val minutes = TimeUnit.MILLISECONDS.toMinutes(milliseconds).toInt() % 60
val seconds = TimeUnit.MILLISECONDS.toSeconds(milliseconds).toInt() % 60
return when {
hours > 0 -> String.format("%d:%02d:%02d", hours, minutes, seconds)
minutes > 0 -> String.format("%02d:%02d", minutes, seconds)
seconds > 0 -> String.format("00:%02d", seconds)
else -> {
"00:00"
}
}
}
You can further change the String format in a way so that you can show your time like ("2 hours ago")
If post.writeTime.toLong() causes a java.lang.NumberFormatException: For input string: "2022-08-31T04:20:45.265Z", I'll have to conclude that the type of post.writeTime is String in ISO standard.
There's a simple way to parse those ISO standards in java.time, in this case you can do
OffsetDateTime.parse(post.writeTime)
and use that to calculate the difference / time elapsed until now (in code: OffsetDateTime.now(ZoneOffset.UTC)). You will need a ZoneOffset because the String returned by post.writeTime also has one (the Z at the end is UTC resp. an offset of +00:00 hours).
The elapsed time can be calculated by means of a java.time.Duration:
val duration = Duration.between(
OffsetDateTime.parse(post.writeTime),
OffsetDateTime.now(ZoneOffset.UTC)
)
A Duration represents elapsed time in hours, minutes, seconds, millis and even nanos, I think. However, only hours, minutes and seconds should matter here (correct me if I'm wrong).
Now the Kotlin magic comes into play: We can write an extension function for Duration, one that simply checks the values top-down (hours first, if zero, use minutes, if zero, use seconds, if zero write some statement):
fun Duration.timeAgo(): String {
return when {
this.toHours() > 0 -> "${this.toHours()} hours ago"
this.toMinutes() > 0 -> "${this.toMinutes()} minutes ago"
this.toSeconds() > 0 -> "${this.toSeconds()} seconds ago"
else -> "a moment ago"
}
}
Example in a main using the time String from your comment below another answer and the code mentioned above (in this answer):
fun main() {
val duration = Duration.between(
OffsetDateTime.parse("2022-08-31T04:20:45.265Z"),
OffsetDateTime.now(ZoneOffset.UTC)
)
println(duration.timeAgo())
}
Result (attention, it depends on the runtime of the code):
3 hours ago
Some examples with Durations of differen values:
fun main() {
val durOne = Duration.ofHours(2).plusMinutes(13).plusSeconds(53)
val durTwo = Duration.ofMinutes(13).plusSeconds(53)
val durThree = Duration.ofSeconds(53).plusMillis(20)
val durFour = Duration.ofMillis(20)
println("${durOne.timeAgo()}")
println("${durTwo.timeAgo()}")
println("${durThree.timeAgo()}")
println("${durFour.timeAgo()}")
}
Output:
2 hours ago
13 minutes ago
53 seconds ago
a moment ago
there were data on my database which I stored before, and I missed that those data had different structure about writetime. So that caused the crash on loading data. After removing those, it worked well.
I'm testing my app today(may 30) whith a custom hour and minute:
var today=LocalDateTime.now().withHour(hour).withMinute(minute).withSecond(0).withNano(0)
But, when i do:
today=today.plusDays(1) //today is: 2022-03-30T10:04
It's return in the Log:
2022-03-30T10:04
UPDATE: Here is the complete code. I'm testing on Android 8.1.0
fun calcEndTime(hour: Int, minute: Int, initinmilliseconds:Long):Long {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
var endtime =LocalDateTime.now().withHour(hour).withMinute(minute).withSecond(0).withNano(0)
val now = LocalDateTime.now().withSecond(0).withNano(0)
val inittime = Instant.ofEpochMilli(initinmilliseconds).atZone(ZoneOffset.UTC).toLocalDateTime()
val days=inittime.dayOfMonth-now.dayOfMonth
if(days==1||days<0){
endtime=endtime.plusDays(1)
Log.d("ZXCV","if ${endtime}")
}
if (endtime.isBefore(now)) {
endtime = endtime.plusDays(1)
}
return endtime.toInstant(ZoneOffset.UTC).toEpochMilli()
}
}
Tried doing it this way, it seems to work just fine š§
fun calcEndTime(hour: Int, minute: Int, initinmilliseconds: Long): LocalDateTime {
var endtime = LocalDateTime.now().withHour(hour).withMinute(minute).withSecond(0).withNano(0)
val now = LocalDateTime.now().withSecond(0).withNano(0)
val inittime = Instant.ofEpochMilli(initinmilliseconds).atZone(ZoneOffset.UTC).toLocalDateTime()
val days = inittime.dayOfMonth - now.dayOfMonth
if (days == 1 || days < 0) {
endtime = endtime.plusDays(1)
Log.d("ZXCV", "if ${endtime}")
}
if (endtime.isBefore(now)) {
endtime = endtime.plusDays(1)
Log.d("ZXCV2", "if ${endtime}")
}
return endtime//.toInstant(ZoneOffset.UTC).toEpochMilli() // try commenting this out to return LocalDateTime instead
}
sample usage:
binding.buttonFirst.setOnClickListener {
val hour = 10
val minute = 4
var today = calcEndTime(hour, minute, 1648706400000)
var test = "TESTING today" + "\n"
test += today.toString() + "\n"
today = today.plusDays(1)
test += today.toString() + "\n"
binding.textviewFirst.text = test
}
Screenshot
I have created below method to get the milliseconds from 12 hour format time :
fun getMillisecondsFromTime(time: String): String {
val formatter = SimpleDateFormat("hh aa")
formatter.isLenient = false
val oldDate = formatter.parse(getLocaleTime(time,"hh aa"))
val oldMillis = oldDate.time
return "" + oldMillis
}
I am calling this method as below for four different times:
var strTime1:String = DateUtils.getMillisecondsFromTime("1 PM")//13 * 3600
var strTime2:String = DateUtils.getMillisecondsFromTime("2 PM")//14 * 3600
var strTime3:String = DateUtils.getMillisecondsFromTime("1 AM")//1 * 3600
var strTime4:String = DateUtils.getMillisecondsFromTime("2 AM")//2 * 3600
Result am getting is wrong. i.e. for 1 PM milliseconds should be 48600 But, am getting :
1Ā PMĀ >>>>>: 45000000, should be 48600
2Ā PMĀ >>>>>: 48600000, should be 50400
What might be the issue?
EDIT : getting local time as below :
fun getLocaleTime(date: String, timeFormat: String): String {
val df = SimpleDateFormat(timeFormat, Locale.ENGLISH)
df.timeZone = TimeZone.getTimeZone("UTC")
val date = df.parse(date)
df.timeZone = TimeZone.getDefault()
val formattedDate = df.format(date)
return formattedDate
}
You need to get hours of the day using Calendar. And then multiply it with 3600. Like
fun getMillisecondsFromTime(time: String): String {
val formatter = SimpleDateFormat("hh aa")
formatter.isLenient = false
val oldDate = formatter.parse(getLocaleTime(time,"hh aa"))
// val oldMillis = oldDate.time
val cal = GregorianCalendar.getInstance()
cal.time = oldDate
val hourIn24Format = cal.get(Calendar.HOUR_OF_DAY)
return "" + (hourIn24Format * 3600)
}
Your current code is returning time in millies from milliseconds since January 1, 1970, 00:00:00 GMT to the time you gave as input.
Note:
I am not sure what you are trying to achieve in this way, but this seems not a good way. If you can explain more about your requirements, I or any other can guide you for better ways.
I am currently working on an android project, which has to collect daily info from google fit api. I have searched a lot, but I have not found answers for 2 questions:
How to get steps bu hours with array. For example from 1pm to 2pm I have walked 100 steps, from 2pm to 3pm 200 steps.
How to get the total amount of time that the user exercised that day.
Thank you very much in advance)
For your first part of point.
If you form a data read request with proper segmented start and end time alongside bucket and aggregation functionality you can retrieve data buckets of each hour.
Below is the code that I am using to retrieve hourly data for any given start and end date.
fun getReadDataRequestBuilderAggregated(startDate: Date, endDate: Date): DataReadRequest? {
val cal = Calendar.getInstance()
cal.time = startDate.setDayStartTime()
var startTime = cal.timeInMillis
cal.time = endDate.setDayEndTime()
var endTime = cal.timeInMillis
return if (startTime>endTime) {
null
} else {
return DataReadRequest.Builder()
.aggregate(DataType.TYPE_CALORIES_EXPENDED, DataType.AGGREGATE_CALORIES_EXPENDED)
.aggregate(DataType.TYPE_STEP_COUNT_DELTA, DataType.AGGREGATE_STEP_COUNT_DELTA)
.bucketByTime(1, TimeUnit.HOURS)
.enableServerQueries()
.setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS).build()
}
}
private fun Date.setDayEndTime(): Date {
val currentTime = Calendar.getInstance().apply {
time = this#setDayEndTime
}
currentTime.set(Calendar.HOUR_OF_DAY, 23)
currentTime.set(Calendar.MINUTE, 59)
currentTime.set(Calendar.SECOND, 59)
return currentTime.time
}
private fun Date.setDayStartTime(): Date {
val currentTime = Calendar.getInstance().apply {
time = this#setDayStartTime
}
currentTime.set(Calendar.HOUR_OF_DAY, 0)
currentTime.set(Calendar.MINUTE, 0)
currentTime.set(Calendar.SECOND, 0)
currentTime.set(Calendar.MILLISECOND,0)
return currentTime.time
}
Hi guys I have a problem using the Google Fit Api. I only receive activity data in specific situations.
I'm using the RxFit library (but I had the same behaviour using the default implementation). When I try this on my own phone (Nexus 5X) with my own account it works perfectly fine. If I try a different account on my phone I receive a success response, but no actual activity data. Same goes for other device and other account. And with my own account on the other device it does not work either. The same behaviour occurs when using the emulator.
My implementation:
fun requestActivities(): Single<DataReadResult> {
val fit = RxFit(context, arrayOf(Fitness.HISTORY_API), arrayOf(Scope(Scopes.FITNESS_ACTIVITY_READ)))
val dataReadRequest = buildRequest(getStartEndTime())
return fit.history().read(dataReadRequest).doOnSuccess { storeDatapoints(it) }
}
private fun storeDatapoints(data: DataReadResult) {
val idlist = activityRepository.all().map { it.activityId }
val activities = data.buckets
.flatMap { it.dataSets }
.flatMap { it.dataPoints }
.filter { point ->
//https://developers.google.com/fit/rest/v1/reference/activity-types
val activity = point.getValue(Field.FIELD_ACTIVITY).asInt()
return#filter activity != 0 && activity != 3 //&& !(109..112).contains(activity)
}
.map { point ->
PersistentExerciseActivity(
activityId = point.timestampNanos.toString(),
date = Instant(point.getTimestamp(TimeUnit.MILLISECONDS)).toDateTime().toLocalDateTime(),
duration = point.getValue(Field.FIELD_DURATION).asInt() / 1000 / 60,
activity = point.getValue(Field.FIELD_ACTIVITY).asActivity(),
apiId = null
)
}
.filter { !idlist.contains(it.activityId) }
activityRepository.store(activities)
}
private fun getStartEndTime(): Pair<Long, Long> {
val cal = Calendar.getInstance()
val now = Date()
cal.time = now
cal.set(Calendar.HOUR_OF_DAY, 0)
cal.set(Calendar.MINUTE, 0)
cal.set(Calendar.MILLISECOND, 0)
cal.set(Calendar.SECOND, 0)
val endTime = cal.timeInMillis
cal.add(Calendar.WEEK_OF_YEAR, -1)
val startTime = cal.timeInMillis
return Pair(startTime, endTime)
}
private fun buildRequest(startEndTime: Pair<Long, Long>): DataReadRequest {
return DataReadRequest.Builder()
.aggregate(DataType.TYPE_ACTIVITY_SEGMENT, DataType.AGGREGATE_ACTIVITY_SUMMARY)
.bucketByTime(1, TimeUnit.DAYS)
.setTimeRange(startEndTime.first, startEndTime.second, TimeUnit.MILLISECONDS)
.enableServerQueries()
.build()
}
Does anyone have some ideas what would be causing this?
Kind regards,
Bryan