1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.healthconnect.controller.recentaccess
18 
19 import android.content.Context
20 import android.widget.ImageView
21 import android.widget.TextView
22 import androidx.core.view.isVisible
23 import androidx.preference.Preference
24 import androidx.preference.PreferenceViewHolder
25 import com.android.healthconnect.controller.R
26 import com.android.healthconnect.controller.permissions.connectedapps.ComparablePreference
27 import com.android.healthconnect.controller.shared.preference.HealthPreference
28 import com.android.healthconnect.controller.utils.TimeSource
29 import com.android.healthconnect.controller.utils.logging.RecentAccessElement
30 import java.time.Instant
31 import java.time.LocalTime
32 import java.time.ZoneId
33 import java.time.format.DateTimeFormatter
34 import java.util.Locale
35 
36 /** Custom preference for displaying Recent access apps, including dash lines for timeline views. */
37 class RecentAccessPreference
38 constructor(
39     context: Context,
40     private val recentAccessApp: RecentAccessEntry,
41     private val timeSource: TimeSource,
42     private val showCategories: Boolean
43 ) : HealthPreference(context), ComparablePreference {
44 
45     private lateinit var appIcon: ImageView
46     private lateinit var appTitle: TextView
47     private lateinit var dataTypesWritten: TextView
48     private lateinit var dataTypesRead: TextView
49     private lateinit var accessTime: TextView
50     private val separator: String = context.getString(R.string.data_type_separator)
51 
52     private val appName = recentAccessApp.metadata.appName
53     private val writtenText: String =
54         context.getString(
55             R.string.write_data_access_label,
<lambda>null56             recentAccessApp.dataTypesWritten.sorted().joinToString(separator) {
57                 context.getString(it)
58             })
59     private val readText: String =
60         context.getString(
61             R.string.read_data_access_label,
<lambda>null62             recentAccessApp.dataTypesRead.sorted().joinToString(separator) {
63                 context.getString(it)
64             })
65     private val formattedTime = formatTime(recentAccessApp.instantTime)
66     // Used to compare this preference to other RecentAccessPreferences
67     val comparableTitle = "${formattedTime}_${appName}_${writtenText}_${readText}"
68 
69     init {
70         layoutResource = R.layout.widget_recent_access_timeline
71         isSelectable = true
72         this.logName = RecentAccessElement.RECENT_ACCESS_ENTRY_BUTTON
73     }
74 
onBindViewHoldernull75     override fun onBindViewHolder(holder: PreferenceViewHolder) {
76         super.onBindViewHolder(holder)
77 
78         appIcon = holder.findViewById(R.id.recent_access_app_icon) as ImageView
79         appIcon.setImageDrawable(recentAccessApp.metadata.icon)
80 
81         appTitle = holder.findViewById(R.id.title) as TextView
82         appTitle.text = appName
83 
84         dataTypesWritten = holder.findViewById(R.id.data_types_written) as TextView
85         dataTypesRead = holder.findViewById(R.id.data_types_read) as TextView
86 
87         if (showCategories) {
88             if (recentAccessApp.dataTypesWritten.isNotEmpty()) {
89                 dataTypesWritten.text = writtenText
90                 dataTypesWritten.isVisible = true
91             }
92 
93             if (recentAccessApp.dataTypesRead.isNotEmpty()) {
94                 dataTypesRead.text = readText
95                 dataTypesRead.isVisible = true
96             }
97         }
98 
99         accessTime = holder.findViewById(R.id.time) as TextView
100         accessTime.text = formattedTime
101         accessTime.contentDescription =
102             context.getString(R.string.recent_access_time_content_descritption, formattedTime)
103     }
104 
isSameItemnull105     override fun isSameItem(preference: Preference): Boolean {
106         return preference is RecentAccessPreference && this == preference
107     }
108 
hasSameContentsnull109     override fun hasSameContents(preference: Preference): Boolean {
110         return preference is RecentAccessPreference &&
111             this.recentAccessApp == preference.recentAccessApp
112     }
113 
formatTimenull114     private fun formatTime(instant: Instant): String {
115         val localTime: LocalTime = instant.atZone(ZoneId.systemDefault()).toLocalTime()
116         return if (timeSource.is24Hour(context)) {
117             localTime.format(DateTimeFormatter.ofPattern("HH:mm"))
118         } else {
119             if (Locale.getDefault() == Locale.KOREA || Locale.getDefault() == Locale.KOREAN) {
120                 localTime.format(DateTimeFormatter.ofPattern("a h:mm"))
121             } else {
122                 localTime.format(DateTimeFormatter.ofPattern("h:mm a"))
123             }
124         }
125     }
126 }
127