From 8c4fedfe28133df017dd63b02f6814ada1e3255d Mon Sep 17 00:00:00 2001 From: sanjay Date: Mon, 11 Mar 2024 17:08:02 +0530 Subject: [PATCH] code to decrypt and login using locally saved credentials --- .../presentation/dashboard/HomeFragment.kt | 394 ++++++++++-------- .../DeviceProvisionFragment.kt | 4 +- 2 files changed, 227 insertions(+), 171 deletions(-) diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index 17cae02..a4c63f5 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt @@ -15,6 +15,8 @@ import android.net.Uri import android.os.BatteryManager import android.os.Build import android.os.Bundle +import android.os.Environment +import android.provider.Settings import android.util.Base64 import android.util.Log import android.view.LayoutInflater @@ -40,6 +42,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest +import com.example.hpostesting.encryption.Encryption import com.example.hpostesting.presentation.KitScanActivity import com.example.hpostesting.presentation.UsbServiceListener import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter @@ -151,69 +154,69 @@ class HomeFragment : Fragment() { } // Now re-subscribe to allUserData -/* hemoCubeViewModel.allLocalData.observe(viewLifecycleOwner) { originalUserDataList -> + /* hemoCubeViewModel.allLocalData.observe(viewLifecycleOwner) { originalUserDataList -> - Log.d("LOCAL_DB OBSERVE", "OBSERVE CALLED") + Log.d("LOCAL_DB OBSERVE", "OBSERVE CALLED") - val resultList = MolbioV2ResultRequest(mutableListOf()) - originalUserDataList.forEach { userData -> - Log.d( - ": USER DATA", - originalUserDataList.count().toString() + " : " + userData._id - ) - var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString() - // Upload results after processing all userData to avoid duplicates and ensure all modifications are done - if(accessToken.isNotEmpty()) { - if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) { - val currentTimeFormatted = SimpleDateFormat( - "yyyy-MM-dd'T'HH:mm:ssZZZZZ", - Locale.getDefault() - ).format(Calendar.getInstance().time) - val bufferIntensityThreshold = - Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId]?.toString() - ?: "defaultThreshold" // Handle possible nulls safely - resultList.results?.add( - MolbioV2Result( - rawData = userData, - analysisId = userData._id, - analysisDate = currentTimeFormatted, - analysisStatus = userData.classificationResult - ?: "defaultStatus", // Handle possible nulls - thresholds = bufferIntensityThreshold, - interpretation = userData.classificationResult - ?: "defaultInterpretation", // Handle possible nulls - testId = userData._id, - testTime = currentTimeFormatted, - collectionTime = currentTimeFormatted, - expiryTime = currentTimeFormatted - ) - ) - } - } - } - Log.d("USER DATA LIST SIZE", resultList.results?.count().toString()) + val resultList = MolbioV2ResultRequest(mutableListOf()) + originalUserDataList.forEach { userData -> + Log.d( + ": USER DATA", + originalUserDataList.count().toString() + " : " + userData._id + ) + var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString() + // Upload results after processing all userData to avoid duplicates and ensure all modifications are done + if(accessToken.isNotEmpty()) { + if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) { + val currentTimeFormatted = SimpleDateFormat( + "yyyy-MM-dd'T'HH:mm:ssZZZZZ", + Locale.getDefault() + ).format(Calendar.getInstance().time) + val bufferIntensityThreshold = + Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId]?.toString() + ?: "defaultThreshold" // Handle possible nulls safely + resultList.results?.add( + MolbioV2Result( + rawData = userData, + analysisId = userData._id, + analysisDate = currentTimeFormatted, + analysisStatus = userData.classificationResult + ?: "defaultStatus", // Handle possible nulls + thresholds = bufferIntensityThreshold, + interpretation = userData.classificationResult + ?: "defaultInterpretation", // Handle possible nulls + testId = userData._id, + testTime = currentTimeFormatted, + collectionTime = currentTimeFormatted, + expiryTime = currentTimeFormatted + ) + ) + } + } + } + Log.d("USER DATA LIST SIZE", resultList.results?.count().toString()) - resultList.results?.forEach { result -> - val userData = result.rawData - Log.d("UserData", userData.toString()) - if (userData != null) { - if (!userData.localFlag) { - hemoCubeViewModel.bulkAddResultTestToDb(userData) + resultList.results?.forEach { result -> + val userData = result.rawData + Log.d("UserData", userData.toString()) + if (userData != null) { + if (!userData.localFlag) { + hemoCubeViewModel.bulkAddResultTestToDb(userData) - } - } - } - resultList.results?.forEach { result -> - result.rawData?.let { sanitizeDoubleValues(it) } - } + } + } + } + resultList.results?.forEach { result -> + result.rawData?.let { sanitizeDoubleValues(it) } + } -// Then, check if there are any results to upload. - if (resultList.results?.isNotEmpty() == true) { - hemoCubeViewModel.uploadResult(resultList) - Log.d("resultcount1", "Uploading sanitized results") - } + // Then, check if there are any results to upload. + if (resultList.results?.isNotEmpty() == true) { + hemoCubeViewModel.uploadResult(resultList) + Log.d("resultcount1", "Uploading sanitized results") + } - }*/ + }*/ hemoCubeViewModel.sendDataToMolbio() hemoCubeViewModel.sendDataToFirebase() @@ -310,26 +313,52 @@ class HomeFragment : Fragment() { var password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString() var userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString() deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").toString() - if(userID.isNotEmpty() && password.isNotEmpty()) { - Log.d("istoken",isTokenAvailable.toString()) - if (!isTokenAvailable) { - Log.d("istoken1",isTokenAvailable.toString()) - hemoCubeViewModel.login(createLoginRequestData(userID, password)) - isTokenAvailable = true - }else if(isTokenAvailable){ - Log.d("istoken7",isTokenAvailable.toString()) - isTokenAvailable = true - hemoCubeViewModel.startPeriodicCheckUpdate() - hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData()) - }else{ - if(isTokenExpired(accessToken)) { - Log.d("istoken8",isTokenAvailable.toString()) - hemoCubeViewModel.login(createLoginRequestData(userID, password)) - } - } + val target = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + val file = File(target, "credentials.txt") //this file contains userID and password to communicate with API. + + if (userID.isNotEmpty() && password.isNotEmpty()) { + Log.d("istoken", isTokenAvailable.toString()) + if (!isTokenAvailable) { + Log.d("istoken1", isTokenAvailable.toString()) + hemoCubeViewModel.login(createLoginRequestData(userID, password)) + isTokenAvailable = true + + } else if (isTokenAvailable) { + Log.d("istoken7", isTokenAvailable.toString()) + isTokenAvailable = true + hemoCubeViewModel.startPeriodicCheckUpdate() + hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData()) + } else { + if (isTokenExpired(accessToken)) { + Log.d("istoken8", isTokenAvailable.toString()) + hemoCubeViewModel.login(createLoginRequestData(userID, password)) + } + } } else if (userID == "deviceIDAPI" && password == "devicePasswordAPI" && deviceId.isNotEmpty()) { fetchDeviceCredentials() + } else if (file.exists()) { + val encryptedString = file.readText() + val encryptionKey = + Settings.Secure.getString(context?.contentResolver, Settings.Secure.ANDROID_ID) + val decryptedMessage: String = Encryption.decrypt(encryptedString, encryptionKey) + val credentials = decryptedMessage.split("\n") + userID = credentials[0] + password = credentials[1] + Toast.makeText(context, "DECRYPTED: $credentials", Toast.LENGTH_SHORT).show() + if (!isTokenAvailable) { + hemoCubeViewModel.login(createLoginRequestData(userID, password)) + isTokenAvailable = true + + } else if (isTokenAvailable) { + isTokenAvailable = true + hemoCubeViewModel.startPeriodicCheckUpdate() + hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData()) + } else { + if (isTokenExpired(accessToken)) { + hemoCubeViewModel.login(createLoginRequestData(userID, password)) + } + } } else { Toast.makeText( requireContext(), @@ -344,7 +373,7 @@ class HomeFragment : Fragment() { updateTokens(response) response.data.data?.accessToken isTokenAvailable = true - Log.d("istoken2",isTokenAvailable.toString()) + Log.d("istoken2", isTokenAvailable.toString()) } is Result.Error -> { @@ -370,7 +399,7 @@ class HomeFragment : Fragment() { when (it) { is Result.Success -> { - Log.d("success,","uploded") + Log.d("success,", "uploded") it.data.data?.forEach { id -> id.rawData?.let { it1 -> hemoCubeViewModel.updateMolbioFlag( @@ -378,7 +407,11 @@ class HomeFragment : Fragment() { ) } } - Toast.makeText(activity, "Molbio Result is successfully uploaded", Toast.LENGTH_LONG) + Toast.makeText( + activity, + "Molbio Result is successfully uploaded", + Toast.LENGTH_LONG + ) .show() } @@ -429,25 +462,29 @@ class HomeFragment : Fragment() { hemoCubeViewModel.checkUpdate.observe(viewLifecycleOwner) { response -> when (response) { is Result.Success -> { - val updatedversion = response.data.data?.version.toString() + val updatedversion = response.data.data?.version.toString() val currentversion = context?.let { ctx -> val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0) val versionName = packageInfo.versionName - val versionCode: Long = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - // From Android P (API level 28), versionCode is deprecated and you should use longVersionCode instead. - packageInfo.longVersionCode - } else { - // For older Android versions, use versionCode (cast it to Long for consistency). - packageInfo.versionCode.toLong() - } + val versionCode: Long = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + // From Android P (API level 28), versionCode is deprecated and you should use longVersionCode instead. + packageInfo.longVersionCode + } else { + // For older Android versions, use versionCode (cast it to Long for consistency). + packageInfo.versionCode.toLong() + } // Use versionName and versionCode as needed - Log.d("AppInfo", "Version Name: $versionName, Version Code: $versionCode") + Log.d( + "AppInfo", + "Version Name: $versionName, Version Code: $versionCode" + ) } - Log.d("versionnow",currentversion.toString()) - Log.d("versionnow",updatedversion.toString()) - if(updatedversion > currentversion.toString()){ + Log.d("versionnow", currentversion.toString()) + Log.d("versionnow", updatedversion.toString()) + if (updatedversion > currentversion.toString()) { hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData()) Toast.makeText( activity, @@ -455,7 +492,7 @@ class HomeFragment : Fragment() { Toast.LENGTH_LONG ) .show() - }else{ + } else { Toast.makeText( activity, "App is Up to date", @@ -491,14 +528,19 @@ class HomeFragment : Fragment() { val downloadDirectory = "NATS" val fileName = "nats_certificate.zip" - val unzipDirectoryPath = requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory" + val unzipDirectoryPath = + requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory" // Check if the directory with extracted files exists. val directory = File(unzipDirectoryPath) if (directory.exists() && directory.isDirectory) { // Assuming if the directory exists, the certificate has been downloaded and extracted. // You can add more specific checks here, e.g., checking for specific files within the directory. - Toast.makeText(requireContext(), "NATS certificate already downloaded and extracted.", Toast.LENGTH_SHORT).show() + Toast.makeText( + requireContext(), + "NATS certificate already downloaded and extracted.", + Toast.LENGTH_SHORT + ).show() return@observe } val file = downloadFile(url, requireContext(), fileName, downloadDirectory) @@ -530,7 +572,7 @@ class HomeFragment : Fragment() { private fun isTokenExpired(token: String): Boolean { - if(token.isNotEmpty()) { + if (token.isNotEmpty()) { val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT)) val jsonPayload = JSONObject(decodedPayload) @@ -539,7 +581,7 @@ class HomeFragment : Fragment() { val currentTimeSeconds = System.currentTimeMillis() / 1000 return exp <= currentTimeSeconds - }else{ + } else { return false } } @@ -554,7 +596,7 @@ class HomeFragment : Fragment() { apply() } isTokenAvailable = true - Log.d("istoken3",isTokenAvailable.toString()) + Log.d("istoken3", isTokenAvailable.toString()) } private fun createLoginRequestData(userID: String, password: String): LoginRequest { @@ -697,9 +739,9 @@ class HomeFragment : Fragment() { putString(Constants.NATS_TOKEN, natsToken) apply() } - if (!isTokenAvailable ) { + if (!isTokenAvailable) { Log.d("istoken0", isTokenAvailable.toString()) - hemoCubeViewModel.login(createLoginRequestData(username, password)) + hemoCubeViewModel.login(createLoginRequestData(username, password)) } } ?: Log.e("fetchDeviceCredentials", "Failed to parse device data.") @@ -904,7 +946,6 @@ class HomeFragment : Fragment() { } - private fun showUploadDialog(context: Context) { val builder = AlertDialog.Builder(context) builder.setTitle(R.string.upload_db_registration_title) @@ -1117,7 +1158,7 @@ class HomeFragment : Fragment() { // } private fun getDeviceId() { - Log.d("HomeFragmentUSb","getDeviceId") + Log.d("HomeFragmentUSb", "getDeviceId") val handler = activity as? DeviceCommunicationHandler handler?.sendAndListenToDevice( HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, @@ -1125,9 +1166,10 @@ class HomeFragment : Fragment() { override fun onUsbRead(data: ByteArray?) { data?.let { val receivedData = String(it, Charset.forName("UTF-8")) - Log.d("HomeFragment","USB data"+receivedData) + Log.d("HomeFragment", "USB data" + receivedData) // Assuming the device ID is the full content of the received data. Adjust if needed. - deviceId = extractDeviceId(receivedData) // Implement this method based on your data format. + deviceId = + extractDeviceId(receivedData) // Implement this method based on your data format. if (deviceId.isNotEmpty()) { // Store the deviceId in SharedPreferences with(sharedPreference.edit()) { @@ -1144,7 +1186,7 @@ class HomeFragment : Fragment() { override fun onUsbError(e: Exception?) { // Handle USB communication error - Log.d("HomeFragment","USB read error"+e.toString()) + Log.d("HomeFragment", "USB read error" + e.toString()) } }) @@ -1156,94 +1198,103 @@ class HomeFragment : Fragment() { val matchResult = regex.find(receivedData) return matchResult?.groups?.get(1)?.value ?: "" } + @SuppressLint("SuspiciousIndentation") private fun checkForUpdate() { try { val db = Firebase.firestore - //val deviceId = deviceId + //val deviceId = deviceId val deviceRef = db.collection("deviceUpdate").document(Constants.DOCUMENT_ID_FOR_UPDATE) deviceRef.get().addOnSuccessListener { documentSnapshot -> - if (documentSnapshot.exists()) { + if (documentSnapshot.exists()) { - val deviceData = - documentSnapshot.toObject(DeviceData::class.java) + val deviceData = + documentSnapshot.toObject(DeviceData::class.java) - // deviceData?.let { data -> + // deviceData?.let { data -> - val deviceVersion = deviceData!!.deviceVersion - val deviceUpdateAvailableGlobal= deviceData.deviceUpdateAvailable - val updatePathGlobal= deviceData.updatePath + val deviceVersion = deviceData!!.deviceVersion + val deviceUpdateAvailableGlobal = deviceData.deviceUpdateAvailable + val updatePathGlobal = deviceData.updatePath - db.collection("devices").whereEqualTo("deviceId", deviceId).get().addOnSuccessListener { documentSnapshotNew -> - if (documentSnapshotNew.documents.isNotEmpty()) { - documentSnapshotNew.documents.forEach{ - val documentIn = it.toObject(DeviceData::class.java) + db.collection("devices").whereEqualTo("deviceId", deviceId).get() + .addOnSuccessListener { documentSnapshotNew -> + if (documentSnapshotNew.documents.isNotEmpty()) { + documentSnapshotNew.documents.forEach { + val documentIn = it.toObject(DeviceData::class.java) - val globalUpdateIgnore = documentIn!!.globalUpdateIgnore - val deviceUpdateAvailable = documentIn.deviceUpdateAvailable - val globalUpdateDone = documentIn.globalUpdateDone - val updatePath = documentIn.updatePath - if(globalUpdateIgnore){ - if(deviceUpdateAvailable){ - val update = db.collection("devices").document(it.id).update("deviceUpdateAvailable",false) - update.addOnSuccessListener { - Log.d("HomeFragmentUpdate","Device local update done") + val globalUpdateIgnore = documentIn!!.globalUpdateIgnore + val deviceUpdateAvailable = documentIn.deviceUpdateAvailable + val globalUpdateDone = documentIn.globalUpdateDone + val updatePath = documentIn.updatePath + if (globalUpdateIgnore) { + if (deviceUpdateAvailable) { + val update = db.collection("devices").document(it.id) + .update("deviceUpdateAvailable", false) + update.addOnSuccessListener { + Log.d( + "HomeFragmentUpdate", + "Device local update done" + ) - initiateUpdate(updatePath) - }.addOnFailureListener{ - Log.e("fetchDeviceUpdate", "update fail.") - } - }else{ - Log.d("HomeFragmentUpdate","Device update not available") - } - }else{ - if(deviceUpdateAvailableGlobal) { - if (!globalUpdateDone) { - val update = - db.collection("devices").document(it.id) - .update("globalUpdateDone", true) - update.addOnSuccessListener { - Log.d( - "HomeFragmentUpdate", - "Device global update done" - ) + initiateUpdate(updatePath) + }.addOnFailureListener { + Log.e("fetchDeviceUpdate", "update fail.") + } + } else { + Log.d( + "HomeFragmentUpdate", + "Device update not available" + ) + } + } else { + if (deviceUpdateAvailableGlobal) { + if (!globalUpdateDone) { + val update = + db.collection("devices").document(it.id) + .update("globalUpdateDone", true) + update.addOnSuccessListener { + Log.d( + "HomeFragmentUpdate", + "Device global update done" + ) - initiateUpdate(updatePathGlobal) - }.addOnFailureListener { - Log.e( - "fetchDeviceUpdate", - "update fail." - ) - } - } + initiateUpdate(updatePathGlobal) + }.addOnFailureListener { + Log.e( + "fetchDeviceUpdate", + "update fail." + ) } } } - - } else { - Log.e("fetchDeviceUpdate", "Document does not exist.") } - }.addOnFailureListener { exception -> - Log.e("fetchDeviceUpdate", "Error fetching device data", exception) } - - // Toast.makeText(requireActivity()," true -version."+deviceVersion+"updatePath.."+updatePath,Toast.LENGTH_LONG).show() + } else { + Log.e("fetchDeviceUpdate", "Document does not exist.") + } + }.addOnFailureListener { exception -> + Log.e("fetchDeviceUpdate", "Error fetching device data", exception) + } - // Log for debugging - Log.d( - "fetchDeviceCredentials", - "deviceVersion: $deviceVersion, Password: $deviceUpdateAvailableGlobal, updatePath: $updatePathGlobal" - ) + // Toast.makeText(requireActivity()," true -version."+deviceVersion+"updatePath.."+updatePath,Toast.LENGTH_LONG).show() + + + // Log for debugging + Log.d( + "fetchDeviceCredentials", + "deviceVersion: $deviceVersion, Password: $deviceUpdateAvailableGlobal, updatePath: $updatePathGlobal" + ) // ?: Log.e("fetchDeviceUpdate", "Failed to parse device data.") - } else { - Log.e("fetchDeviceUpdate", "Document does not exist.") - } + } else { + Log.e("fetchDeviceUpdate", "Document does not exist.") } + } .addOnFailureListener { exception -> Log.e("fetchDeviceUpdate", "Error fetching device data", exception) } @@ -1265,7 +1316,8 @@ class HomeFragment : Fragment() { request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) request.setDestinationInExternalFilesDir(requireActivity(), "Updates", "update.apk") - val downloadManager = requireActivity().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + val downloadManager = + requireActivity().getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager downloadId = downloadManager.enqueue(request) // Register a BroadcastReceiver to receive the download complete event @@ -1275,12 +1327,15 @@ class HomeFragment : Fragment() { requireActivity().registerReceiver(downloadReceiver, filter, RECEIVER_EXPORTED) } } + private fun extractApkUrl(responseBody: ResponseBody): String { return responseBody.string() } + private fun isValidHttpUrl(url: String): Boolean { return url.startsWith("http://") || url.startsWith("https://") } + private val downloadReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context?, intent: Intent?) { val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) @@ -1294,8 +1349,11 @@ class HomeFragment : Fragment() { val file = File(requireActivity().getExternalFilesDir("Updates"), "update.apk") file.setReadable(true, false) // Ensure the file is readable - val pInfo = requireActivity().baseContext.packageManager.getPackageInfo(requireActivity().baseContext.packageName, 0) - Log.d("HomeFragmentShowInfo",pInfo.packageName.toString()) + val pInfo = requireActivity().baseContext.packageManager.getPackageInfo( + requireActivity().baseContext.packageName, + 0 + ) + Log.d("HomeFragmentShowInfo", pInfo.packageName.toString()) val uri: Uri = FileProvider.getUriForFile( requireActivity(), "${pInfo.packageName}.fileprovider", @@ -1318,7 +1376,7 @@ class HomeFragment : Fragment() { } override fun onDestroy() { - if(isRegistered) { + if (isRegistered) { try { requireActivity().unregisterReceiver(downloadReceiver) } catch (e: Exception) { diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt index cd70ad2..553193e 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt @@ -233,7 +233,7 @@ class DeviceProvisionFragment : Fragment() { } private fun encryptAndSaveToFile(username: String, password: String) { - val messageToEncrypt = "deviceID\n$username\n$password" + val messageToEncrypt = "$username\n$password" val encryptionKey = Settings.Secure.getString(context?.contentResolver, Settings.Secure.ANDROID_ID) val encryptedString = Encryption.encrypt(messageToEncrypt, encryptionKey) @@ -245,12 +245,10 @@ class DeviceProvisionFragment : Fragment() { file.createNewFile() } - val fos = FileOutputStream(file) file.writeText(encryptedString) Log.d("Encrypted Message", encryptedString) - fos.close() } }