• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * 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.Intent
20 import android.os.Bundle
21 import android.view.LayoutInflater
22 import android.view.View
23 import android.view.ViewGroup
24 import android.widget.FrameLayout
25 import androidx.core.os.bundleOf
26 import androidx.core.view.isVisible
27 import androidx.fragment.app.viewModels
28 import androidx.navigation.fragment.findNavController
29 import androidx.preference.Preference
30 import androidx.preference.PreferenceGroup
31 import androidx.recyclerview.widget.RecyclerView
32 import com.android.healthconnect.controller.R
33 import com.android.healthconnect.controller.permissions.shared.Constants
34 import com.android.healthconnect.controller.recentaccess.RecentAccessViewModel.RecentAccessState
35 import com.android.healthconnect.controller.shared.preference.HealthPreferenceFragment
36 import com.android.healthconnect.controller.utils.logging.HealthConnectLogger
37 import com.android.healthconnect.controller.utils.logging.PageName
38 import com.android.healthconnect.controller.utils.logging.RecentAccessElement
39 import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
40 import dagger.hilt.android.AndroidEntryPoint
41 import javax.inject.Inject
42 
43 /** Recent access fragment showing a timeline of apps that have recently accessed Health Connect. */
44 @AndroidEntryPoint(HealthPreferenceFragment::class)
45 class RecentAccessFragment : Hilt_RecentAccessFragment() {
46 
47     companion object {
48         private const val RECENT_ACCESS_TODAY_KEY = "recent_access_today"
49         private const val RECENT_ACCESS_YESTERDAY_KEY = "recent_access_yesterday"
50         private const val RECENT_ACCESS_NO_DATA_KEY = "no_data"
51     }
52 
53     init {
54         this.setPageName(PageName.RECENT_ACCESS_PAGE)
55     }
56 
57     @Inject lateinit var logger: HealthConnectLogger
58 
59     private val viewModel: RecentAccessViewModel by viewModels()
60     private lateinit var contentParent: FrameLayout
61     private lateinit var fab: ExtendedFloatingActionButton
62     private var recyclerView: RecyclerView? = null
63 
64     private val mRecentAccessTodayPreferenceGroup: PreferenceGroup? by lazy {
65         preferenceScreen.findPreference(RECENT_ACCESS_TODAY_KEY)
66     }
67 
68     private val mRecentAccessYesterdayPreferenceGroup: PreferenceGroup? by lazy {
69         preferenceScreen.findPreference(RECENT_ACCESS_YESTERDAY_KEY)
70     }
71 
72     private val mRecentAccessNoDataPreference: Preference? by lazy {
73         preferenceScreen.findPreference(RECENT_ACCESS_NO_DATA_KEY)
74     }
75 
76     override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
77         super.onCreatePreferences(savedInstanceState, rootKey)
78         setPreferencesFromResource(R.xml.recent_access_preference_screen, rootKey)
79     }
80 
81     override fun onCreateView(
82         inflater: LayoutInflater,
83         container: ViewGroup?,
84         savedInstanceState: Bundle?
85     ): View? {
86         val rootView = super.onCreateView(inflater, container, savedInstanceState)
87 
88         contentParent = requireActivity().findViewById(android.R.id.content)
89         inflater.inflate(R.layout.widget_floating_action_button, contentParent)
90 
91         fab = contentParent.findViewById(R.id.extended_fab)
92         fab.isVisible = true
93 
94         recyclerView = rootView?.findViewById(R.id.recycler_view)
95         val bottomPadding =
96             resources.getDimensionPixelSize(R.dimen.recent_access_fab_bottom_padding)
97         recyclerView?.setPadding(0, 0, 0, bottomPadding)
98 
99         return rootView
100     }
101 
102     override fun onPause() {
103         // Prevents FAB from being permanently attached to the activity layout
104         contentParent.removeView(fab)
105         super.onPause()
106     }
107 
108     override fun onResume() {
109         super.onResume()
110         viewModel.loadRecentAccessApps()
111 
112         if (fab.parent == null) {
113             contentParent.addView(fab)
114         }
115         logger.logImpression(RecentAccessElement.MANAGE_PERMISSIONS_FAB)
116     }
117 
118     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
119         super.onViewCreated(view, savedInstanceState)
120 
121         viewModel.loadRecentAccessApps()
122         viewModel.recentAccessApps.observe(viewLifecycleOwner) { state ->
123             when (state) {
124                 is RecentAccessState.Loading -> {
125                     setLoading(true)
126                 }
127                 is RecentAccessState.Error -> {
128                     setError(true)
129                 }
130                 is RecentAccessState.WithData -> {
131                     setLoading(false)
132                     updateRecentApps(state.recentAccessEntries)
133                 }
134             }
135         }
136     }
137 
138     private fun updateRecentApps(recentAppsList: List<RecentAccessEntry>) {
139         mRecentAccessTodayPreferenceGroup?.removeAll()
140         mRecentAccessYesterdayPreferenceGroup?.removeAll()
141         mRecentAccessNoDataPreference?.isVisible = false
142 
143         if (recentAppsList.isEmpty()) {
144             mRecentAccessYesterdayPreferenceGroup?.isVisible = false
145             mRecentAccessTodayPreferenceGroup?.isVisible = false
146             mRecentAccessNoDataPreference?.isVisible = true
147             fab.isVisible = false
148         } else {
149             // if the first entry is yesterday, we don't need the 'Today' section
150             mRecentAccessTodayPreferenceGroup?.isVisible = recentAppsList[0].isToday
151 
152             // if the last entry is today, we don't need the 'Yesterday' section
153             mRecentAccessYesterdayPreferenceGroup?.isVisible = !recentAppsList.last().isToday
154 
155             fab.setOnClickListener {
156                 logger.logInteraction(RecentAccessElement.MANAGE_PERMISSIONS_FAB)
157                 findNavController()
158                     .navigate(R.id.action_recentAccessFragment_to_connectedAppsFragment)
159             }
160 
161             recentAppsList.forEachIndexed { index, recentApp ->
162                 val isLastUsage =
163                     (index == recentAppsList.size - 1) ||
164                         (recentApp.isToday &&
165                             index < recentAppsList.size - 1 &&
166                             !recentAppsList[index + 1].isToday)
167                 val newPreference =
168                     RecentAccessPreference(requireContext(), recentApp, true).also {
169                         if (!recentApp.isInactive) {
170                             // Do not set click listeners for inactive apps
171                             it.setOnPreferenceClickListener {
172                                 findNavController()
173                                     .navigate(
174                                         R.id.action_recentAccessFragment_to_connectedAppFragment,
175                                         bundleOf(
176                                             Intent.EXTRA_PACKAGE_NAME to
177                                                 recentApp.metadata.packageName,
178                                             Constants.EXTRA_APP_NAME to recentApp.metadata.appName))
179                                 true
180                             }
181                         }
182                     }
183 
184                 if (recentApp.isToday) {
185                     mRecentAccessTodayPreferenceGroup?.addPreference(newPreference)
186                     if (!isLastUsage) {
187                         mRecentAccessTodayPreferenceGroup?.addPreference(
188                             DividerPreference(requireContext()))
189                     }
190                 } else {
191                     mRecentAccessYesterdayPreferenceGroup?.addPreference(newPreference)
192                     if (!isLastUsage) {
193                         mRecentAccessYesterdayPreferenceGroup?.addPreference(
194                             DividerPreference(requireContext()))
195                     }
196                 }
197             }
198         }
199     }
200 }
201