1 /*
2  * Copyright (C) 2022 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.systemui.screenshot
18 
19 import android.content.ComponentName
20 import android.content.Context
21 import android.content.pm.PackageManager
22 import android.content.pm.PackageManager.ComponentInfoFlags
23 import android.graphics.drawable.Drawable
24 import android.os.UserHandle
25 import android.os.UserManager
26 import android.util.Log
27 import android.view.View
28 import android.view.ViewGroup
29 import android.widget.ImageView
30 import android.widget.TextView
31 import com.android.systemui.res.R
32 import javax.inject.Inject
33 
34 /**
35  * Handles work profile first run, determining whether a first run UI should be shown and populating
36  * that UI if needed.
37  */
38 class WorkProfileMessageController
39 @Inject
40 constructor(
41     private val context: Context,
42     private val userManager: UserManager,
43     private val packageManager: PackageManager,
44 ) {
45 
46     /**
47      * @return a populated WorkProfileFirstRunData object if a work profile first run message should
48      *   be shown
49      */
onScreenshotTakennull50     fun onScreenshotTaken(userHandle: UserHandle?): WorkProfileFirstRunData? {
51         if (userHandle == null) return null
52 
53         if (userManager.isManagedProfile(userHandle.identifier) && !messageAlreadyDismissed()) {
54             var badgedIcon: Drawable? = null
55             var label: CharSequence? = null
56             val fileManager =
57                 fileManagerComponentName()
58                     ?: return WorkProfileFirstRunData(defaultFileAppName(), null)
59             try {
60                 val info = packageManager.getActivityInfo(fileManager, ComponentInfoFlags.of(0L))
61                 val icon = packageManager.getActivityIcon(fileManager)
62                 badgedIcon = packageManager.getUserBadgedIcon(icon, userHandle)
63                 label = info.loadLabel(packageManager)
64             } catch (e: PackageManager.NameNotFoundException) {
65                 Log.w(TAG, "Component $fileManager not found")
66             }
67 
68             // If label wasn't loaded, use a default
69             return WorkProfileFirstRunData(label ?: defaultFileAppName(), badgedIcon)
70         }
71         return null
72     }
73 
74     /**
75      * Use the provided WorkProfileFirstRunData to populate the work profile first run UI in the
76      * given view.
77      */
populateViewnull78     fun populateView(view: ViewGroup, data: WorkProfileFirstRunData, animateOut: () -> Unit) {
79         if (data.icon != null) {
80             // Replace the default icon if one is provided.
81             val imageView: ImageView = view.requireViewById<ImageView>(R.id.screenshot_message_icon)
82             imageView.setImageDrawable(data.icon)
83         }
84         val messageContent = view.requireViewById<TextView>(R.id.screenshot_message_content)
85         messageContent.text =
86             view.context.getString(R.string.screenshot_work_profile_notification, data.appName)
87         view.requireViewById<View>(R.id.message_dismiss_button).setOnClickListener {
88             animateOut()
89             onMessageDismissed()
90         }
91     }
92 
messageAlreadyDismissednull93     private fun messageAlreadyDismissed(): Boolean {
94         return sharedPreference().getBoolean(PREFERENCE_KEY, false)
95     }
96 
onMessageDismissednull97     private fun onMessageDismissed() {
98         val editor = sharedPreference().edit()
99         editor.putBoolean(PREFERENCE_KEY, true)
100         editor.apply()
101     }
102 
sharedPreferencenull103     private fun sharedPreference() =
104         context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE)
105 
106     private fun fileManagerComponentName() =
107         ComponentName.unflattenFromString(context.getString(R.string.config_screenshotFilesApp))
108 
109     private fun defaultFileAppName() = context.getString(R.string.screenshot_default_files_app_name)
110 
111     data class WorkProfileFirstRunData constructor(val appName: CharSequence, val icon: Drawable?)
112 
113     companion object {
114         const val TAG = "WorkProfileMessageCtrl"
115         const val SHARED_PREFERENCES_NAME = "com.android.systemui.screenshot"
116         const val PREFERENCE_KEY = "work_profile_first_run"
117     }
118 }
119