1 /* 2 * Copyright (C) 2025 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.privatespace.filetransfer 18 19 import android.app.DownloadManager 20 import android.app.Notification 21 import android.app.NotificationChannel 22 import android.app.NotificationManager 23 import android.app.PendingIntent 24 import android.content.Context 25 import android.content.Intent 26 import com.android.privatespace.R 27 import java.util.concurrent.atomic.AtomicBoolean 28 29 /** A helper class to send file transfer progress and completion notifications to the user */ 30 class NotificationsHelper(private val context: Context) { 31 32 companion object { 33 private val NOTIFICATION_CHANNEL_ID: String = "FileTransferProgress" 34 const val NOTIFICATION_ID: Int = 1 35 } 36 37 private var canUpdateProgressNotification = AtomicBoolean(true) 38 39 private var notificationManager: NotificationManager = 40 context.getSystemService(NotificationManager::class.java) 41 createNotificationChannelnull42 fun createNotificationChannel() { 43 val channel = 44 NotificationChannel( 45 NOTIFICATION_CHANNEL_ID, 46 context.getString(R.string.filetransfer_notification_channel_name), 47 NotificationManager.IMPORTANCE_HIGH, 48 ) 49 channel.description = 50 context.getString(R.string.filetransfer_notification_channel_description) 51 notificationManager.createNotificationChannel(channel) 52 } 53 displayCompletionNotificationnull54 fun displayCompletionNotification(numberOfFiles: Int, keepOriginal: Boolean) { 55 canUpdateProgressNotification.getAndSet(false) 56 val notification = buildCompletionNotification(numberOfFiles, keepOriginal) 57 notificationManager.notify(NOTIFICATION_ID, notification) 58 } 59 updateProgressNotificationnull60 fun updateProgressNotification(progress: Int, numberOfFiles: Int, keepOriginal: Boolean) { 61 val notification = buildProgressNotification(progress, numberOfFiles, keepOriginal) 62 if (canUpdateProgressNotification.acquire) { 63 notificationManager.notify(NOTIFICATION_ID, notification) 64 } 65 } 66 buildProgressNotificationnull67 fun buildProgressNotification( 68 progress: Int, 69 numberOfFiles: Int, 70 keepOriginal: Boolean, 71 ): Notification { 72 val openFileIntent = Intent(DownloadManager.ACTION_VIEW_DOWNLOADS) 73 openFileIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 74 75 val notificationTitle = 76 context.resources.getString( 77 if (keepOriginal) R.string.filetransfer_notification_copy_progress_title 78 else R.string.filetransfer_notification_move_progress_title, 79 numberOfFiles, 80 ) 81 val notificationText = 82 context 83 .getResources() 84 .getString( 85 if (keepOriginal) R.string.filetransfer_notification_copy_progress_text 86 else R.string.filetransfer_notification_move_progress_text 87 ) 88 89 val pendingIntent = 90 PendingIntent.getActivity( 91 context, 92 0, 93 openFileIntent, 94 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, 95 ) 96 97 return baseNotificationBuilder(notificationTitle, notificationText, context) 98 .setOngoing(true) 99 .setProgress(100, progress, false) 100 .setContentIntent(pendingIntent) 101 .addAction( 102 Notification.Action.Builder( 103 R.drawable.ic_private_profile_badge, 104 context.resources.getString( 105 R.string.filetransfer_notification_action_label 106 ), 107 pendingIntent, 108 ) 109 .build() 110 ) 111 .build() 112 } 113 buildCompletionNotificationnull114 private fun buildCompletionNotification( 115 numberOfFiles: Int, 116 keepOriginal: Boolean, 117 ): Notification { 118 val openFileIntent = Intent(DownloadManager.ACTION_VIEW_DOWNLOADS) 119 openFileIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 120 121 val notificationTitle = 122 context.resources.getString( 123 if (keepOriginal) R.string.filetransfer_notification_copy_complete_title 124 else R.string.filetransfer_notification_move_complete_title, 125 numberOfFiles, 126 ) 127 val notificationText = 128 context.resources.getString( 129 if (keepOriginal) R.string.filetransfer_notification_copy_complete_text 130 else R.string.filetransfer_notification_move_complete_text 131 ) 132 133 val pendingIntent = 134 PendingIntent.getActivity( 135 context, 136 0, 137 openFileIntent, 138 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, 139 ) 140 141 return baseNotificationBuilder(notificationTitle, notificationText, context) 142 .setOngoing(false) 143 .setContentIntent(pendingIntent) 144 .setAutoCancel(true) 145 .addAction( 146 Notification.Action.Builder( 147 R.drawable.ic_private_profile_badge, 148 context.resources.getString( 149 R.string.filetransfer_notification_action_label 150 ), 151 pendingIntent, 152 ) 153 .build() 154 ) 155 .build() 156 } 157 baseNotificationBuildernull158 private fun baseNotificationBuilder( 159 contentTitle: String, 160 contentText: String, 161 context: Context, 162 ): Notification.Builder { 163 return Notification.Builder(context, NOTIFICATION_CHANNEL_ID) 164 .setContentTitle(contentTitle) 165 .setContentText(contentText) 166 .setSmallIcon(R.drawable.ic_private_profile_badge) 167 .setOnlyAlertOnce(true) 168 } 169 } 170