/* * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.privatespace.logging import com.android.privatespace.PrivateSpaceStatsLog /** * A utility object for logging the results of file transfer operations to the Private Space. It * handles logging for success, partial success, and failure scenarios to PrivateSpaceStatsLog. */ object FileTransferResultLogger { /** * Logs a file transfer result event. * * The final transfer result is determined based on the contents of [filesLoggingDetails]: * - **Success**: If there is at least one successful file transfer and no failures. * - **Failure**: If there are no successful file transfers. * - **Partial Success**: If there are both successful and failed file transfers. * * @param keepOriginal Specifies the type of operation: `false` for a move operation, or `true` * for a copy operation. * @param filesSelectedCount The total number of files the user initially selected to transfer. * @param filesLoggingDetails An object containing aggregated details about the successful and * failed files, including counts, total sizes, and MIME types. */ fun logMoveContentResultEvent( keepOriginal: Boolean, filesSelectedCount: Int, filesLoggingDetails: FilesLoggingDetails, ) { val operationType = if (keepOriginal) PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__OPERATION_TYPE__OPERATION_COPY else PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__OPERATION_TYPE__OPERATION_MOVE val transferResult = when { filesLoggingDetails.successFileMimeTypes.isNotEmpty() && filesLoggingDetails.failedFileDetails.isEmpty() -> { PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__TRANSFER_RESULT__TRANSFER_RESULT_SUCCESS } filesLoggingDetails.successFileMimeTypes.isEmpty() -> { PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__TRANSFER_RESULT__TRANSFER_RESULT_FAILURE } else -> { PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__TRANSFER_RESULT__TRANSFER_RESULT_PARTIAL_SUCCESS } } PrivateSpaceStatsLog.write( PrivateSpaceStatsLog.PRIVATE_SPACE_MOVE_CONTENT_EVENT, operationType, filesSelectedCount, /* transfer_result */ transferResult, /* files_success_count */ filesLoggingDetails.successFileMimeTypes.size, /* files_failure_count */ filesLoggingDetails.failedFileDetails.size, /* total_success_files_size_bucket */ if ( filesLoggingDetails.successFileMimeTypes.isEmpty() ) 0 else FileSizeBucketConverter.getFileSizeBucket( filesLoggingDetails.totalSuccessFilesSize ), /* total_failure_files_size_bucket */ if ( filesLoggingDetails.failedFileDetails.isEmpty() ) 0 else FileSizeBucketConverter.getFileSizeBucket(filesLoggingDetails.totalFailedFilesSize), /* failed_file_error_codes */ filesLoggingDetails.failedFileDetails .map { it.errorCode } .toIntArray(), /* failed_file_mime_types */ filesLoggingDetails.failedFileDetails .map { MimeTypeConverter.getMimeTypeCategory(it.mimeType) } .toIntArray(), /* success_file_mime_types */ filesLoggingDetails.successFileMimeTypes .map { MimeTypeConverter.getMimeTypeCategory(it) } .toIntArray(), /* notification_event */ 0, // TODO(b/400696164): Implement duration calculation. /* duration_ms */ 0, ) } fun logTransferFailedOnPrechecks( errorCode: Int, numberOfFiles: Int, totalSizeFilesSelected: Long, ) { PrivateSpaceStatsLog.write( PrivateSpaceStatsLog.PRIVATE_SPACE_MOVE_CONTENT_EVENT, /* operation_type */ 0, /* files_selected_count */ numberOfFiles, /* transfer_result */ PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__TRANSFER_RESULT__TRANSFER_RESULT_FAILURE, /* files_success_count */ 0, /* files_failure_count */ numberOfFiles, /* total_success_files_size_bucket */ 0, /* total_failure_files_size_bucket */ FileSizeBucketConverter.getFileSizeBucket( totalSizeFilesSelected ), /* failed_file_error_codes */ IntArray(numberOfFiles) { errorCode }, /* failed_file_mime_types */ null, /* success_file_mime_types */ null, /* notification_event */ 0, /* duration_ms */ 0, ) } fun logAnotherTransferInProgressEvent() { val errorCode = PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__FAILED_FILE_ERROR_CODES__TRANSFER_ERROR_ANOTHER_TRANSFER_IN_PROGRESS PrivateSpaceStatsLog.write( PrivateSpaceStatsLog.PRIVATE_SPACE_MOVE_CONTENT_EVENT, /* operation_type */ 0, /* files_selected_count */ 0, /* transfer_result */ PrivateSpaceStatsLog .PRIVATE_SPACE_MOVE_CONTENT_EVENT__TRANSFER_RESULT__TRANSFER_RESULT_FAILURE, /* files_success_count */ 0, /* files_failure_count */ 0, /* total_success_files_size_bucket */ 0, /* total_failure_files_size_bucket */ 0, /* failed_file_error_codes */ intArrayOf(errorCode), /* failed_file_mime_types */ null, /* success_file_mime_types */ null, /* notification_event */ 0, /* duration_ms */ 0, ) } }