From 37f8b72a30aacaf55c805a9ded48275017d43150 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Thu, 14 Mar 2019 08:43:26 -0700 Subject: [PATCH 1/2] Add an API to launch the ongoing usage dialog. Bug: 128690096 Test: Send intent and open the dialog. Change-Id: Idc77a0f366ffc3ffe593dce66f28a27fdbe76b1d --- api/system-current.txt | 3 ++- core/java/android/content/Intent.java | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/api/system-current.txt b/api/system-current.txt index 9548a27fc33ae..f32239426c156 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1426,8 +1426,9 @@ package android.content { field public static final String ACTION_RESOLVE_INSTANT_APP_PACKAGE = "android.intent.action.RESOLVE_INSTANT_APP_PACKAGE"; field @RequiresPermission(android.Manifest.permission.REVIEW_ACCESSIBILITY_SERVICES) public static final String ACTION_REVIEW_ACCESSIBILITY_SERVICES = "android.intent.action.REVIEW_ACCESSIBILITY_SERVICES"; field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_APP_PERMISSION_USAGE = "android.intent.action.REVIEW_APP_PERMISSION_USAGE"; + field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE"; field public static final String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS"; - field public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE"; + field @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE"; field public static final String ACTION_ROLLBACK_COMMITTED = "android.intent.action.ROLLBACK_COMMITTED"; field public static final String ACTION_SHOW_SUSPENDED_APP_DETAILS = "android.intent.action.SHOW_SUSPENDED_APP_DETAILS"; field @Deprecated public static final String ACTION_SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED"; diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 93a9daced987d..6bb9498043905 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -2078,6 +2078,9 @@ public class Intent implements Parcelable, Cloneable { *

* Output: Nothing. *

+ *

+ * This requires {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS} permission. + *

* * @see #EXTRA_PERMISSION_NAME * @see #EXTRA_PERMISSION_GROUP_NAME @@ -2086,10 +2089,34 @@ public class Intent implements Parcelable, Cloneable { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_REVIEW_PERMISSION_USAGE = "android.intent.action.REVIEW_PERMISSION_USAGE"; + /** + * Activity action: Launch UI to review ongoing app uses of permissions. + *

+ * Input: {@link #EXTRA_DURATION_MILLIS} specifies the minimum number of milliseconds of recent + * activity to show (optional). Must be non-negative. + *

+ *

+ * Output: Nothing. + *

+ *

+ * This requires {@link android.Manifest.permission#GRANT_RUNTIME_PERMISSIONS} permission. + *

+ * + * @see #EXTRA_DURATION_MILLIS + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_REVIEW_ONGOING_PERMISSION_USAGE = + "android.intent.action.REVIEW_ONGOING_PERMISSION_USAGE"; + /** * Activity action: Launch UI to review uses of permissions for a single app. *

From f8b6292dcbc9751dc3780f36279ec8d49f655db6 Mon Sep 17 00:00:00 2001 From: Joel Galenson Date: Fri, 15 Mar 2019 12:51:16 -0700 Subject: [PATCH 2/2] Launch external ongoing usage dialog instead of internal one. Bug: 128690096 Test: Tap chip to get the dialog. Change-Id: I0eced80ab2341678a6e7b02b1d2d5395ad96d4a5 --- cmds/statsd/src/atoms.proto | 1 - .../systemui/privacy/OngoingPrivacyDialog.kt | 160 ------------------ .../systemui/qs/QuickStatusBarHeader.java | 10 +- 3 files changed, 2 insertions(+), 169 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 1dbbbc5595ba4..d20901c6bf105 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -3419,7 +3419,6 @@ message HiddenApiUsed { * - When user clicks privacy chip * - How does the user exit the Privacy Dialog * Logged from: - * packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt * packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java */ message PrivacyIndicatorsInteracted { diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt deleted file mode 100644 index cf170187cdaa9..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2018 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.systemui.privacy - -import android.app.AlertDialog -import android.app.Dialog -import android.content.Context -import android.content.DialogInterface -import android.content.Intent -import android.content.pm.PackageManager -import android.content.res.ColorStateList -import android.os.UserHandle -import android.provider.Settings -import android.util.IconDrawableFactory -import android.util.StatsLog -import android.view.Gravity -import android.view.LayoutInflater -import android.view.View -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView -import com.android.systemui.Dependency -import com.android.systemui.R -import com.android.systemui.plugins.ActivityStarter -import java.util.concurrent.TimeUnit - -class OngoingPrivacyDialog constructor( - private val context: Context, - private val dialogBuilder: PrivacyDialogBuilder -) { - - private val iconSize = context.resources.getDimensionPixelSize( - R.dimen.ongoing_appops_dialog_icon_size) - private val iconColor = context.resources.getColor( - com.android.internal.R.color.text_color_primary, context.theme) - private val iconMargin = context.resources.getDimensionPixelSize( - R.dimen.ongoing_appops_dialog_icon_margin) - private val iconFactory = IconDrawableFactory.newInstance(context, true) - private var dismissDialog: (() -> Unit)? = null - private val appsAndTypes = dialogBuilder.appsAndTypes - .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps - { it.second.min() }, - { it.first })) - - fun createDialog(): Dialog { - val builder = AlertDialog.Builder(context).apply { - setPositiveButton(R.string.ongoing_privacy_dialog_ok, - object : DialogInterface.OnClickListener { - override fun onClick(dialog: DialogInterface?, which: Int) { - StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, - StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_DISMISS) - } - }) - setNeutralButton(R.string.ongoing_privacy_dialog_open_settings, - object : DialogInterface.OnClickListener { - val intent = Intent(Settings.ACTION_PRIVACY_SETTINGS).putExtra( - Intent.EXTRA_DURATION_MILLIS, TimeUnit.MINUTES.toMillis(1)) - - @Suppress("DEPRECATION") - override fun onClick(dialog: DialogInterface?, which: Int) { - StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, StatsLog - .PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_PRIVACY_SETTINGS) - Dependency.get(ActivityStarter::class.java) - .postStartActivityDismissingKeyguard(intent, 0) - } - }) - } - builder.setView(getContentView()) - val dialog = builder.create() - dismissDialog = dialog::dismiss - return dialog - } - - fun getContentView(): View { - val layoutInflater = LayoutInflater.from(context) - val contentView = layoutInflater.inflate(R.layout.ongoing_privacy_dialog_content, null) - - val title = contentView.findViewById(R.id.title) as TextView - val appsList = contentView.findViewById(R.id.items_container) as LinearLayout - - title.setText(dialogBuilder.getDialogTitle()) - - val numItems = appsAndTypes.size - for (i in 0..(numItems - 1)) { - val item = appsAndTypes[i] - addAppItem(appsList, item.first, item.second, dialogBuilder.types.size > 1) - } - return contentView - } - - @Suppress("DEPRECATION") - private fun addAppItem( - itemList: LinearLayout, - app: PrivacyApplication, - types: List, - showIcons: Boolean = true - ) { - val layoutInflater = LayoutInflater.from(context) - val item = layoutInflater.inflate(R.layout.ongoing_privacy_dialog_item, itemList, false) - val appIcon = item.findViewById(R.id.app_icon) as ImageView - val appName = item.findViewById(R.id.app_name) as TextView - val icons = item.findViewById(R.id.icons) as LinearLayout - - val lp = LinearLayout.LayoutParams(iconSize, iconSize).apply { - gravity = Gravity.CENTER_VERTICAL - marginStart = iconMargin - } - - app.icon.let { - appIcon.setImageDrawable(iconFactory.getShadowedIcon(it)) - } - - appName.text = app.applicationName - if (showIcons) { - dialogBuilder.generateIconsForApp(types).forEachIndexed { index, it -> - it.setBounds(0, 0, iconSize, iconSize) - val image = ImageView(context).apply { - imageTintList = ColorStateList.valueOf(iconColor) - setImageDrawable(it) - } - image.contentDescription = types[index].getName(context) - icons.addView(image, lp) - } - icons.visibility = View.VISIBLE - } else { - icons.visibility = View.GONE - } - try { - // Check if package exists - context.packageManager.getPackageInfo(app.packageName, 0) - item.setOnClickListener(object : View.OnClickListener { - val intent = Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS) - .putExtra(Intent.EXTRA_PACKAGE_NAME, app.packageName) - .putExtra(Intent.EXTRA_USER, UserHandle.getUserHandleForUid(app.uid)) - override fun onClick(v: View?) { - StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, - StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__DIALOG_LINE_ITEM, - app.packageName) - Dependency.get(ActivityStarter::class.java) - .postStartActivityDismissingKeyguard(intent, 0) - dismissDialog?.invoke() - } - }) - } catch (e: PackageManager.NameNotFoundException) {} - - itemList.addView(item) - } -} diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 4862b9eddc851..c897b9c3b4671 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -23,7 +23,6 @@ import android.animation.AnimatorListenerAdapter; import android.annotation.ColorInt; import android.app.ActivityManager; import android.app.AlarmManager; -import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -62,7 +61,6 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.DarkIconDispatcher; import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver; import com.android.systemui.privacy.OngoingPrivacyChip; -import com.android.systemui.privacy.OngoingPrivacyDialog; import com.android.systemui.privacy.PrivacyDialogBuilder; import com.android.systemui.privacy.PrivacyItem; import com.android.systemui.privacy.PrivacyItemController; @@ -71,7 +69,6 @@ import com.android.systemui.statusbar.phone.PhoneStatusBarView; import com.android.systemui.statusbar.phone.StatusBarIconController; import com.android.systemui.statusbar.phone.StatusBarIconController.TintedIconManager; import com.android.systemui.statusbar.phone.StatusIconContainer; -import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.Clock; import com.android.systemui.statusbar.policy.DateView; import com.android.systemui.statusbar.policy.NextAlarmController; @@ -561,11 +558,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_CLICKED); mUiHandler.post(() -> { - Dialog mDialog = new OngoingPrivacyDialog(mContext, builder).createDialog(); - SystemUIDialog.setShowForAllUsers(mDialog, false); - SystemUIDialog.registerDismissListener(mDialog); - SystemUIDialog.setWindowOnTop(mDialog); - mActivityStarter.postQSRunnableDismissingKeyguard(() -> mDialog.show()); + mActivityStarter.postStartActivityDismissingKeyguard( + new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0); mHost.collapsePanels(); }); }