blob: cf170187cdaa921657067e154dd40935decf261f [file] [log] [blame]
Fabian Kozynski12638242018-10-12 15:33:41 -04001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5 * except in compliance with the License. You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11 * KIND, either express or implied. See the License for the specific language governing
12 * permissions and limitations under the License.
13 */
14
15package com.android.systemui.privacy
16
17import android.app.AlertDialog
18import android.app.Dialog
19import android.content.Context
20import android.content.DialogInterface
Fabian Kozynskief124492018-11-02 11:02:11 -040021import android.content.Intent
Fabian Kozynski873e1932019-01-29 18:33:07 -050022import android.content.pm.PackageManager
Fabian Kozynskief124492018-11-02 11:02:11 -040023import android.content.res.ColorStateList
Fabian Kozynski0d03da32019-01-28 10:35:28 -050024import android.os.UserHandle
Fabian Kozynskieac70d82019-01-31 15:04:56 -050025import android.provider.Settings
Fabian Kozynskiba219722019-01-11 16:30:18 -050026import android.util.IconDrawableFactory
Fabian Kozynskibfd6d852019-02-15 15:08:16 -050027import android.util.StatsLog
Fabian Kozynskibb68be02018-11-19 12:58:01 -050028import android.view.Gravity
Fabian Kozynski12638242018-10-12 15:33:41 -040029import android.view.LayoutInflater
30import android.view.View
Fabian Kozynski12638242018-10-12 15:33:41 -040031import android.widget.ImageView
32import android.widget.LinearLayout
33import android.widget.TextView
34import com.android.systemui.Dependency
35import com.android.systemui.R
36import com.android.systemui.plugins.ActivityStarter
Joel Galenson4bed4922019-01-22 10:56:10 -080037import java.util.concurrent.TimeUnit
Fabian Kozynski12638242018-10-12 15:33:41 -040038
39class OngoingPrivacyDialog constructor(
Fabian Kozynski20b609c2019-02-11 12:56:27 -050040 private val context: Context,
41 private val dialogBuilder: PrivacyDialogBuilder
Fabian Kozynski12638242018-10-12 15:33:41 -040042) {
43
Fabian Kozynskibb68be02018-11-19 12:58:01 -050044 private val iconSize = context.resources.getDimensionPixelSize(
45 R.dimen.ongoing_appops_dialog_icon_size)
46 private val iconColor = context.resources.getColor(
Fabian Kozynski12638242018-10-12 15:33:41 -040047 com.android.internal.R.color.text_color_primary, context.theme)
Fabian Kozynskibb68be02018-11-19 12:58:01 -050048 private val iconMargin = context.resources.getDimensionPixelSize(
49 R.dimen.ongoing_appops_dialog_icon_margin)
Fabian Kozynskiba219722019-01-11 16:30:18 -050050 private val iconFactory = IconDrawableFactory.newInstance(context, true)
Fabian Kozynski0d03da32019-01-28 10:35:28 -050051 private var dismissDialog: (() -> Unit)? = null
Fabian Kozynskia37d5232019-02-01 10:14:26 -050052 private val appsAndTypes = dialogBuilder.appsAndTypes
53 .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps
54 { it.second.min() },
55 { it.first }))
Fabian Kozynskiba219722019-01-11 16:30:18 -050056
Fabian Kozynski12638242018-10-12 15:33:41 -040057 fun createDialog(): Dialog {
Fabian Kozynskief124492018-11-02 11:02:11 -040058 val builder = AlertDialog.Builder(context).apply {
Fabian Kozynskibfd6d852019-02-15 15:08:16 -050059 setPositiveButton(R.string.ongoing_privacy_dialog_ok,
60 object : DialogInterface.OnClickListener {
61 override fun onClick(dialog: DialogInterface?, which: Int) {
62 StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
63 StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_DISMISS)
64 }
65 })
Fabian Kozynski0d03da32019-01-28 10:35:28 -050066 setNeutralButton(R.string.ongoing_privacy_dialog_open_settings,
Fabian Kozynski12638242018-10-12 15:33:41 -040067 object : DialogInterface.OnClickListener {
Fabian Kozynski2d6c1252019-02-05 12:57:34 -050068 val intent = Intent(Settings.ACTION_PRIVACY_SETTINGS).putExtra(
Joel Galenson4bed4922019-01-22 10:56:10 -080069 Intent.EXTRA_DURATION_MILLIS, TimeUnit.MINUTES.toMillis(1))
Fabian Kozynski12638242018-10-12 15:33:41 -040070
Aurimas Liutikasf1f63f62019-01-03 13:00:58 -080071 @Suppress("DEPRECATION")
Fabian Kozynski12638242018-10-12 15:33:41 -040072 override fun onClick(dialog: DialogInterface?, which: Int) {
Fabian Kozynskibfd6d852019-02-15 15:08:16 -050073 StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, StatsLog
74 .PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_PRIVACY_SETTINGS)
Fabian Kozynski554fb772019-01-09 17:04:56 -050075 Dependency.get(ActivityStarter::class.java)
76 .postStartActivityDismissingKeyguard(intent, 0)
Fabian Kozynski12638242018-10-12 15:33:41 -040077 }
78 })
Fabian Kozynski12638242018-10-12 15:33:41 -040079 }
80 builder.setView(getContentView())
Fabian Kozynski0d03da32019-01-28 10:35:28 -050081 val dialog = builder.create()
82 dismissDialog = dialog::dismiss
83 return dialog
Fabian Kozynski12638242018-10-12 15:33:41 -040084 }
85
86 fun getContentView(): View {
87 val layoutInflater = LayoutInflater.from(context)
88 val contentView = layoutInflater.inflate(R.layout.ongoing_privacy_dialog_content, null)
89
Fabian Kozynskief124492018-11-02 11:02:11 -040090 val title = contentView.findViewById(R.id.title) as TextView
91 val appsList = contentView.findViewById(R.id.items_container) as LinearLayout
Fabian Kozynski12638242018-10-12 15:33:41 -040092
Fabian Kozynskief124492018-11-02 11:02:11 -040093 title.setText(dialogBuilder.getDialogTitle())
94
Fabian Kozynskia37d5232019-02-01 10:14:26 -050095 val numItems = appsAndTypes.size
Fabian Kozynskief124492018-11-02 11:02:11 -040096 for (i in 0..(numItems - 1)) {
Fabian Kozynskia37d5232019-02-01 10:14:26 -050097 val item = appsAndTypes[i]
Fabian Kozynskief124492018-11-02 11:02:11 -040098 addAppItem(appsList, item.first, item.second, dialogBuilder.types.size > 1)
Fabian Kozynski12638242018-10-12 15:33:41 -040099 }
100 return contentView
101 }
102
Fabian Kozynski0d03da32019-01-28 10:35:28 -0500103 @Suppress("DEPRECATION")
Fabian Kozynskief124492018-11-02 11:02:11 -0400104 private fun addAppItem(
105 itemList: LinearLayout,
106 app: PrivacyApplication,
107 types: List<PrivacyType>,
108 showIcons: Boolean = true
109 ) {
110 val layoutInflater = LayoutInflater.from(context)
111 val item = layoutInflater.inflate(R.layout.ongoing_privacy_dialog_item, itemList, false)
112 val appIcon = item.findViewById(R.id.app_icon) as ImageView
113 val appName = item.findViewById(R.id.app_name) as TextView
114 val icons = item.findViewById(R.id.icons) as LinearLayout
Fabian Kozynski12638242018-10-12 15:33:41 -0400115
Fabian Kozynski508422b2018-12-20 10:58:17 -0500116 val lp = LinearLayout.LayoutParams(iconSize, iconSize).apply {
Fabian Kozynskibb68be02018-11-19 12:58:01 -0500117 gravity = Gravity.CENTER_VERTICAL
118 marginStart = iconMargin
119 }
120
Fabian Kozynski508422b2018-12-20 10:58:17 -0500121 app.icon.let {
Fabian Kozynskiba219722019-01-11 16:30:18 -0500122 appIcon.setImageDrawable(iconFactory.getShadowedIcon(it))
Fabian Kozynskief124492018-11-02 11:02:11 -0400123 }
124
125 appName.text = app.applicationName
126 if (showIcons) {
Fabian Kozynski6024e862019-01-11 13:13:40 -0500127 dialogBuilder.generateIconsForApp(types).forEachIndexed { index, it ->
Fabian Kozynskief124492018-11-02 11:02:11 -0400128 it.setBounds(0, 0, iconSize, iconSize)
129 val image = ImageView(context).apply {
130 imageTintList = ColorStateList.valueOf(iconColor)
131 setImageDrawable(it)
132 }
Fabian Kozynski6024e862019-01-11 13:13:40 -0500133 image.contentDescription = types[index].getName(context)
Fabian Kozynskibb68be02018-11-19 12:58:01 -0500134 icons.addView(image, lp)
Fabian Kozynski12638242018-10-12 15:33:41 -0400135 }
Fabian Kozynskief124492018-11-02 11:02:11 -0400136 icons.visibility = View.VISIBLE
137 } else {
138 icons.visibility = View.GONE
Fabian Kozynski12638242018-10-12 15:33:41 -0400139 }
Fabian Kozynski873e1932019-01-29 18:33:07 -0500140 try {
141 // Check if package exists
142 context.packageManager.getPackageInfo(app.packageName, 0)
143 item.setOnClickListener(object : View.OnClickListener {
Fabian Kozynski2d6c1252019-02-05 12:57:34 -0500144 val intent = Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS)
Fabian Kozynski873e1932019-01-29 18:33:07 -0500145 .putExtra(Intent.EXTRA_PACKAGE_NAME, app.packageName)
146 .putExtra(Intent.EXTRA_USER, UserHandle.getUserHandleForUid(app.uid))
147 override fun onClick(v: View?) {
Fabian Kozynskibfd6d852019-02-15 15:08:16 -0500148 StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED,
149 StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_LINE_ITEM,
150 app.packageName)
Fabian Kozynski873e1932019-01-29 18:33:07 -0500151 Dependency.get(ActivityStarter::class.java)
152 .postStartActivityDismissingKeyguard(intent, 0)
153 dismissDialog?.invoke()
154 }
155 })
156 } catch (e: PackageManager.NameNotFoundException) {}
157
Fabian Kozynskief124492018-11-02 11:02:11 -0400158 itemList.addView(item)
Fabian Kozynski12638242018-10-12 15:33:41 -0400159 }
160}