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.ImageView 30 import android.widget.TextView 31 import android.widget.Toast 32 import androidx.activity.result.ActivityResult 33 import androidx.activity.result.ActivityResultLauncher 34 import androidx.activity.result.contract.ActivityResultContracts 35 import androidx.fragment.app.Fragment 36 import androidx.fragment.app.viewModels 37 import androidx.navigation.fragment.findNavController 38 import com.android.healthconnect.controller.R 39 import com.android.healthconnect.controller.exportimport.api.DocumentProviders 40 import com.android.healthconnect.controller.exportimport.api.ExportSettingsViewModel 41 import com.android.healthconnect.controller.exportimport.api.isLocalFile 42 import com.android.healthconnect.controller.utils.DeviceInfoUtils 43 import com.android.settingslib.widget.LinkTextView 44 import dagger.hilt.android.AndroidEntryPoint 45 import javax.inject.Inject 46 47 /** Fragment to allow the user to find and select the backup file to import and restore. */ 48 @AndroidEntryPoint(Fragment::class) 49 class ImportSourceLocationFragment : Hilt_ImportSourceLocationFragment() { 50 private val contract = ActivityResultContracts.StartActivityForResult() 51 private val saveResultLauncher: ActivityResultLauncher<Intent> = 52 registerForActivityResult(contract, ::onSave) 53 54 private val viewModel: ExportSettingsViewModel by viewModels() 55 56 @Inject lateinit var deviceInfoUtils: DeviceInfoUtils 57 58 override fun onCreateView( 59 inflater: LayoutInflater, 60 container: ViewGroup?, 61 savedInstanceState: Bundle? 62 ): View? { 63 val view = inflater.inflate(R.layout.import_source_location_screen, container, false) 64 val pageHeaderView = view.findViewById<TextView>(R.id.page_header_text) 65 val pageHeaderIconView = view.findViewById<ImageView>(R.id.page_header_icon) 66 val footerView = view.findViewById<View>(R.id.export_import_footer) 67 val playStoreView = view.findViewById<LinkTextView>(R.id.export_import_go_to_play_store) 68 val cancelButton = view.findViewById<Button>(R.id.export_import_cancel_button) 69 val nextButton = view.findViewById<Button>(R.id.export_import_next_button) 70 71 pageHeaderView.text = getString(R.string.import_source_location_title) 72 pageHeaderIconView.setImageResource(R.drawable.ic_import_data) 73 nextButton.text = getString(R.string.import_next_button) 74 cancelButton.text = getString(R.string.import_cancel_button) 75 76 cancelButton.setOnClickListener { requireActivity().finish() } 77 78 if (deviceInfoUtils.isPlayStoreAvailable(requireContext())) { 79 playStoreView?.setVisibility(VISIBLE) 80 playStoreView?.setOnClickListener { 81 findNavController().navigate(R.id.action_importSourceLocationFragment_to_playStore) 82 } 83 } 84 85 val documentProvidersViewBinder = DocumentProvidersViewBinder() 86 val documentProvidersList = view.findViewById<ViewGroup>(R.id.import_document_providers) 87 viewModel.documentProviders.observe(viewLifecycleOwner) { providers -> 88 documentProvidersList.removeAllViews() 89 nextButton.setOnClickListener {} 90 nextButton.setEnabled(false) 91 92 when (providers) { 93 is DocumentProviders.Loading -> { 94 // Do nothing 95 } 96 is DocumentProviders.LoadingFailed -> { 97 Toast.makeText(activity, R.string.default_error, Toast.LENGTH_LONG).show() 98 } 99 is DocumentProviders.WithData -> { 100 documentProvidersViewBinder.bindDocumentProvidersView( 101 providers.providers, documentProvidersList, inflater) { root -> 102 nextButton.setOnClickListener { 103 saveResultLauncher.launch( 104 Intent(Intent.ACTION_OPEN_DOCUMENT) 105 .addFlags( 106 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or 107 Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 108 .setType("application/zip") 109 .addCategory(Intent.CATEGORY_OPENABLE) 110 .putExtra(DocumentsContract.EXTRA_INITIAL_URI, root.uri)) 111 } 112 nextButton.setEnabled(true) 113 } 114 115 if (providers.providers.size > 1) { 116 footerView.setVisibility(GONE) 117 } else { 118 footerView.setVisibility(VISIBLE) 119 } 120 } 121 } 122 } 123 124 return view 125 } 126 127 private fun onSave(result: ActivityResult) { 128 if (result.resultCode == Activity.RESULT_OK) { 129 val fileUri = result.data?.data ?: return 130 if (isLocalFile(fileUri)) { 131 Toast.makeText(activity, R.string.import_invalid_storage, Toast.LENGTH_LONG).show() 132 } else { 133 // TODO: b/339189778 - Add test when import API is done. 134 findNavController() 135 .navigate(R.id.action_importSourceLocationFragment_to_importDecryptionFragment) 136 } 137 } 138 } 139 } 140