1 /*
<lambda>null2  * Copyright (C) 2024 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.exportimport
18 
19 import android.app.Activity
20 import android.content.Intent
21 import android.os.Bundle
22 import android.provider.DocumentsContract
23 import android.view.LayoutInflater
24 import android.view.View
25 import android.view.View.GONE
26 import android.view.View.VISIBLE
27 import android.view.ViewGroup
28 import android.widget.Button
29 import android.widget.Toast
30 import androidx.activity.result.ActivityResult
31 import androidx.activity.result.ActivityResultLauncher
32 import androidx.activity.result.contract.ActivityResultContracts
33 import androidx.fragment.app.Fragment
34 import androidx.fragment.app.activityViewModels
35 import androidx.navigation.fragment.findNavController
36 import com.android.healthconnect.controller.R
37 import com.android.healthconnect.controller.exportimport.api.DocumentProviders
38 import com.android.healthconnect.controller.exportimport.api.ExportSettingsViewModel
39 import com.android.healthconnect.controller.exportimport.api.isLocalFile
40 import com.android.healthconnect.controller.utils.DeviceInfoUtils
41 import com.android.settingslib.widget.LinkTextView
42 import dagger.hilt.android.AndroidEntryPoint
43 import javax.inject.Inject
44 
45 /** Export destination fragment for Health Connect. */
46 @AndroidEntryPoint(Fragment::class)
47 class ExportDestinationFragment : Hilt_ExportDestinationFragment() {
48 
49     private val contract = ActivityResultContracts.StartActivityForResult()
50     private val saveResultLauncher: ActivityResultLauncher<Intent> =
51         registerForActivityResult(contract, ::onSave)
52 
53     private val viewModel: ExportSettingsViewModel by activityViewModels()
54 
55     @Inject lateinit var deviceInfoUtils: DeviceInfoUtils
56 
57     override fun onCreateView(
58         inflater: LayoutInflater,
59         container: ViewGroup?,
60         savedInstanceState: Bundle?
61     ): View? {
62         val view = inflater.inflate(R.layout.export_destination_screen, container, false)
63         val footerView = view.findViewById<View>(R.id.export_import_footer)
64         val playStoreView = view.findViewById<LinkTextView>(R.id.export_import_go_to_play_store)
65         val backButton = view.findViewById<Button>(R.id.export_import_cancel_button)
66         val nextButton = view.findViewById<Button>(R.id.export_import_next_button)
67 
68         backButton?.text = getString(R.string.export_back_button)
69         backButton?.setOnClickListener {
70             findNavController()
71                 .navigate(R.id.action_exportDestinationFragment_to_exportFrequencyFragment)
72         }
73 
74         nextButton.text = getString(R.string.export_next_button)
75         nextButton.setEnabled(false)
76 
77         if (deviceInfoUtils.isPlayStoreAvailable(requireContext())) {
78             playStoreView?.setVisibility(VISIBLE)
79             playStoreView?.setOnClickListener {
80                 findNavController().navigate(R.id.action_exportDestinationFragment_to_playStore)
81             }
82         }
83 
84         val documentProvidersViewBinder = DocumentProvidersViewBinder()
85         val documentProvidersList = view.findViewById<ViewGroup>(R.id.export_document_providers)
86         viewModel.documentProviders.observe(viewLifecycleOwner) { providers ->
87             documentProvidersList.removeAllViews()
88             nextButton.setOnClickListener {}
89             nextButton.setEnabled(false)
90 
91             when (providers) {
92                 is DocumentProviders.Loading -> {
93                     // Do nothing
94                 }
95                 is DocumentProviders.LoadingFailed -> {
96                     Toast.makeText(activity, R.string.default_error, Toast.LENGTH_LONG).show()
97                 }
98                 is DocumentProviders.WithData -> {
99                     documentProvidersViewBinder.bindDocumentProvidersView(
100                         providers.providers, documentProvidersList, inflater) { root ->
101                             nextButton.setOnClickListener {
102                                 saveResultLauncher.launch(
103                                     Intent(Intent.ACTION_CREATE_DOCUMENT)
104                                         .addFlags(
105                                             Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
106                                                 Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
107                                         .setType("application/zip")
108                                         .addCategory(Intent.CATEGORY_OPENABLE)
109                                         .putExtra(DocumentsContract.EXTRA_INITIAL_URI, root.uri))
110                             }
111                             nextButton.setEnabled(true)
112                         }
113 
114                     if (providers.providers.size > 1) {
115                         footerView.setVisibility(GONE)
116                     } else {
117                         footerView.setVisibility(VISIBLE)
118                     }
119                 }
120             }
121         }
122 
123         return view
124     }
125 
126     private fun onSave(result: ActivityResult) {
127         if (result.resultCode == Activity.RESULT_OK) {
128             val fileUri = result.data?.data ?: return
129             if (isLocalFile(fileUri)) {
130                 Toast.makeText(activity, R.string.export_invalid_storage, Toast.LENGTH_LONG).show()
131             } else {
132                 viewModel.updateExportUriWithSelectedFrequency(fileUri)
133                 requireActivity().finish()
134             }
135         }
136     }
137 }
138