diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java index 58e80c7c104f7..9e23c28a07114 100644 --- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java +++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java @@ -136,13 +136,6 @@ public final class SystemUiDeviceConfigFlags { */ public static final String HASH_SALT_MAX_DAYS = "hash_salt_max_days"; - // Flag related to Privacy Indicators - - /** - * Whether the Permissions Hub is showing. - */ - public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; - // Flags related to Assistant /** diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index ee79653d92ac6..f68d0349e6a02 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -60,21 +60,6 @@ 96dp 128dp - - 48dp - - 15dp - - 24dp - - 12dp - - 6dp - - 4dp - - 12dp - @dimen/car_primary_icon_size @*android:dimen/car_single_line_list_item_height diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml deleted file mode 100644 index b7b21fa53b626..0000000000000 --- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml deleted file mode 100644 index dce9ce16e9cd3..0000000000000 --- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml deleted file mode 100644 index 5595b130e0417..0000000000000 --- a/packages/SystemUI/res/layout/ongoing_privacy_text_item.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - \ No newline at end of file diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml index cd9f780ca2492..867676799b31b 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_header_system_icons.xml @@ -14,7 +14,7 @@ ** See the License for the specific language governing permissions and ** limitations under the License. --> - - - - - - - - - - - - + diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 86ef0310b4ebb..cb5f24885d097 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -463,8 +463,6 @@ com.android.systemui - 5 - com.android.launcher3 diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 64b2892efc9a7..aeb9348bbc1ce 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1057,47 +1057,6 @@ 0px - - - 16dp - - 16dp - - 24dp - - 12dp - - 32dp - - 24dp - - 48dp - - 24dp - - 24dp - - 18dp - - 20sp - - 16sp - - 32dp - - 8dp - - 8dp - - 0dp - - 2dp - - @dimen/status_bar_icon_drawing_size - - 16dp - - 1dp diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 99da058a2e2bc..1dd5496b27f9a 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2444,27 +2444,6 @@ app for debugging. Will not be seen by users. [CHAR LIMIT=20] --> Dump SysUI Heap - - %1$s is using your %2$s. - - - Applications are using your %s. - - - ,\u0020 - - - \u0020and\u0020 - - - camera - - - location - - - microphone - Sensors off diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 96fbcbba6e8b4..926d01685075c 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -227,18 +227,6 @@ @color/dark_mode_qs_icon_color_single_tone - - - - diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index c55b0d92f86d3..6821265df28b6 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -56,7 +56,6 @@ import com.android.systemui.plugins.VolumeDialogController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.power.EnhancedEstimates; import com.android.systemui.power.PowerUI; -import com.android.systemui.privacy.PrivacyItemController; import com.android.systemui.recents.OverviewProxyService; import com.android.systemui.recents.Recents; import com.android.systemui.shared.plugins.PluginManager; @@ -298,7 +297,6 @@ public class Dependency { @Inject Lazy mSensorPrivacyManager; @Inject Lazy mAutoHideController; @Inject Lazy mForegroundServiceNotificationListener; - @Inject Lazy mPrivacyItemController; @Inject @BgLooper Lazy mBgLooper; @Inject @BgHandler Lazy mBgHandler; @Inject @MainLooper Lazy mMainLooper; @@ -497,7 +495,6 @@ public class Dependency { mProviders.put(ForegroundServiceNotificationListener.class, mForegroundServiceNotificationListener::get); mProviders.put(ClockManager.class, mClockManager::get); - mProviders.put(PrivacyItemController.class, mPrivacyItemController::get); mProviders.put(ActivityManagerWrapper.class, mActivityManagerWrapper::get); mProviders.put(DevicePolicyManagerWrapper.class, mDevicePolicyManagerWrapper::get); mProviders.put(PackageManagerWrapper.class, mPackageManagerWrapper::get); diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt deleted file mode 100644 index a5a915b88cad6..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt +++ /dev/null @@ -1,110 +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.content.Context -import android.util.AttributeSet -import android.view.Gravity -import android.view.ViewGroup -import android.widget.FrameLayout -import android.widget.ImageView -import android.widget.LinearLayout -import com.android.systemui.R - -class OngoingPrivacyChip @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttrs: Int = 0, - defStyleRes: Int = 0 -) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) { - - private val iconMarginExpanded = context.resources.getDimensionPixelSize( - R.dimen.ongoing_appops_chip_icon_margin_expanded) - private val iconMarginCollapsed = context.resources.getDimensionPixelSize( - R.dimen.ongoing_appops_chip_icon_margin_collapsed) - private val iconSize = - context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size) - private val iconColor = context.resources.getColor( - R.color.status_bar_clock_color, context.theme) - private val sidePadding = - context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_side_padding) - private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg) - private lateinit var iconsContainer: LinearLayout - private lateinit var back: FrameLayout - var expanded = false - set(value) { - if (value != field) { - field = value - updateView() - } - } - - var builder = PrivacyDialogBuilder(context, emptyList()) - var privacyList = emptyList() - set(value) { - field = value - builder = PrivacyDialogBuilder(context, value) - updateView() - } - - override fun onFinishInflate() { - super.onFinishInflate() - - back = findViewById(R.id.background) - iconsContainer = findViewById(R.id.icons_container) - } - - // Should only be called if the builder icons or app changed - private fun updateView() { - back.background = if (expanded) backgroundDrawable else null - val padding = if (expanded) sidePadding else 0 - back.setPaddingRelative(padding, 0, padding, 0) - fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) { - iconsContainer.removeAllViews() - dialogBuilder.generateIcons().forEachIndexed { i, it -> - it.mutate() - it.setTint(iconColor) - val image = ImageView(context).apply { - setImageDrawable(it) - scaleType = ImageView.ScaleType.CENTER_INSIDE - } - iconsContainer.addView(image, iconSize, iconSize) - if (i != 0) { - val lp = image.layoutParams as MarginLayoutParams - lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed - image.layoutParams = lp - } - } - } - - if (!privacyList.isEmpty()) { - generateContentDescription() - setIcons(builder, iconsContainer) - val lp = iconsContainer.layoutParams as FrameLayout.LayoutParams - lp.gravity = Gravity.CENTER_VERTICAL or - (if (expanded) Gravity.CENTER_HORIZONTAL else Gravity.END) - iconsContainer.layoutParams = lp - } else { - iconsContainer.removeAllViews() - } - requestLayout() - } - - private fun generateContentDescription() { - val typesText = builder.joinTypes() - contentDescription = context.getString( - R.string.ongoing_privacy_chip_content_multiple_apps, typesText) - } -} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt deleted file mode 100644 index d08a3733703b0..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyDialogBuilder.kt +++ /dev/null @@ -1,56 +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.content.Context -import android.graphics.drawable.Drawable -import com.android.systemui.R - -class PrivacyDialogBuilder(private val context: Context, itemsList: List) { - - val appsAndTypes: List>> - val types: List - private val separator = context.getString(R.string.ongoing_privacy_dialog_separator) - private val lastSeparator = context.getString(R.string.ongoing_privacy_dialog_last_separator) - - init { - appsAndTypes = itemsList.groupBy({ it.application }, { it.privacyType }) - .toList() - .sortedWith(compareBy({ -it.second.size }, // Sort by number of AppOps - { it.second.min() })) // Sort by "smallest" AppOpp (Location is largest) - types = itemsList.map { it.privacyType }.distinct().sorted() - } - - fun generateIconsForApp(types: List): List { - return types.sorted().map { it.getIcon(context) } - } - - fun generateIcons() = types.map { it.getIcon(context) } - - private fun List.joinWithAnd(): StringBuilder { - return subList(0, size - 1).joinTo(StringBuilder(), separator = separator).apply { - append(lastSeparator) - append(this@joinWithAnd.last()) - } - } - - fun joinTypes(): String { - return when (types.size) { - 0 -> "" - 1 -> types[0].getName(context) - else -> types.map { it.getName(context) }.joinWithAnd().toString() - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt deleted file mode 100644 index 290942412eedf..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt +++ /dev/null @@ -1,80 +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.content.Context -import android.content.pm.ApplicationInfo -import android.content.pm.PackageManager -import android.graphics.drawable.Drawable -import android.os.UserHandle -import android.util.IconDrawableFactory -import com.android.systemui.R - -typealias Privacy = PrivacyType - -enum class PrivacyType(private val nameId: Int, val iconId: Int) { - // This is uses the icons used by the corresponding permission groups in the AndroidManifest - TYPE_CAMERA(R.string.privacy_type_camera, - com.android.internal.R.drawable.perm_group_camera), - TYPE_MICROPHONE(R.string.privacy_type_microphone, - com.android.internal.R.drawable.perm_group_microphone), - TYPE_LOCATION(R.string.privacy_type_location, - com.android.internal.R.drawable.perm_group_location); - - fun getName(context: Context) = context.resources.getString(nameId) - - fun getIcon(context: Context) = context.resources.getDrawable(iconId, context.theme) -} - -data class PrivacyItem( - val privacyType: PrivacyType, - val application: PrivacyApplication -) - -data class PrivacyApplication(val packageName: String, val uid: Int, val context: Context) - : Comparable { - - override fun compareTo(other: PrivacyApplication): Int { - return applicationName.compareTo(other.applicationName) - } - - private val applicationInfo: ApplicationInfo? by lazy { - try { - val userHandle = UserHandle.getUserHandleForUid(uid) - context.createPackageContextAsUser(packageName, 0, userHandle).getPackageManager() - .getApplicationInfo(packageName, 0) - } catch (_: PackageManager.NameNotFoundException) { - null - } - } - val icon: Drawable by lazy { - applicationInfo?.let { - try { - val iconFactory = IconDrawableFactory.newInstance(context, true) - iconFactory.getBadgedIcon(it, UserHandle.getUserId(uid)) - } catch (_: Exception) { - null - } - } ?: context.getDrawable(android.R.drawable.sym_def_app_icon) - } - - val applicationName: String by lazy { - applicationInfo?.let { - context.packageManager.getApplicationLabel(it) as String - } ?: packageName - } - - override fun toString() = "PrivacyApplication(packageName=$packageName, uid=$uid)" -} diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt deleted file mode 100644 index d592492820c19..0000000000000 --- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt +++ /dev/null @@ -1,299 +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.ActivityManager -import android.app.AppOpsManager -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter -import android.os.Handler -import android.os.Looper -import android.os.Message -import android.os.UserHandle -import android.os.UserManager -import android.provider.DeviceConfig -import com.android.internal.annotations.VisibleForTesting -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags -import com.android.systemui.Dumpable -import com.android.systemui.R -import com.android.systemui.appops.AppOpItem -import com.android.systemui.appops.AppOpsController -import com.android.systemui.broadcast.BroadcastDispatcher -import com.android.systemui.dagger.qualifiers.BgHandler -import com.android.systemui.dagger.qualifiers.MainHandler -import java.io.FileDescriptor -import java.io.PrintWriter -import java.lang.ref.WeakReference -import javax.inject.Inject -import javax.inject.Singleton - -fun isPermissionsHubEnabled() = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false) - -@Singleton -class PrivacyItemController @Inject constructor( - private val context: Context, - private val appOpsController: AppOpsController, - @MainHandler private val uiHandler: Handler, - @BgHandler private val bgHandler: Handler, - private val broadcastDispatcher: BroadcastDispatcher -) : Dumpable { - - @VisibleForTesting - internal companion object { - val OPS = intArrayOf(AppOpsManager.OP_CAMERA, - AppOpsManager.OP_RECORD_AUDIO, - AppOpsManager.OP_COARSE_LOCATION, - AppOpsManager.OP_FINE_LOCATION) - val intents = listOf(Intent.ACTION_USER_FOREGROUND, - Intent.ACTION_MANAGED_PROFILE_ADDED, - Intent.ACTION_MANAGED_PROFILE_REMOVED) - const val TAG = "PrivacyItemController" - const val SYSTEM_UID = 1000 - const val MSG_ADD_CALLBACK = 0 - const val MSG_REMOVE_CALLBACK = 1 - const val MSG_UPDATE_LISTENING_STATE = 2 - } - - @VisibleForTesting - internal var privacyList = emptyList() - @Synchronized get() = field.toList() // Returns a shallow copy of the list - @Synchronized set - - private val userManager = context.getSystemService(UserManager::class.java) - private var currentUserIds = emptyList() - private var listening = false - val systemApp = - PrivacyApplication(context.getString(R.string.device_services), SYSTEM_UID, context) - private val callbacks = mutableListOf>() - private val messageHandler = H(WeakReference(this), uiHandler.looper) - - private val notifyChanges = Runnable { - val list = privacyList - callbacks.forEach { it.get()?.privacyChanged(list) } - } - - private val updateListAndNotifyChanges = Runnable { - updatePrivacyList() - uiHandler.post(notifyChanges) - } - - private var indicatorsAvailable = isPermissionsHubEnabled() - @VisibleForTesting - internal val devicePropertiesChangedListener = - object : DeviceConfig.OnPropertiesChangedListener { - override fun onPropertiesChanged(properties: DeviceConfig.Properties) { - if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) && - properties.getKeyset().contains( - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) { - indicatorsAvailable = properties.getBoolean( - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false) - messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE) - messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE) - } - } - } - - private val cb = object : AppOpsController.Callback { - override fun onActiveStateChanged( - code: Int, - uid: Int, - packageName: String, - active: Boolean - ) { - val userId = UserHandle.getUserId(uid) - if (userId in currentUserIds) { - update(false) - } - } - } - - @VisibleForTesting - internal var userSwitcherReceiver = Receiver() - set(value) { - context.unregisterReceiver(field) - field = value - registerReceiver() - } - - init { - DeviceConfig.addOnPropertiesChangedListener( - DeviceConfig.NAMESPACE_PRIVACY, - context.mainExecutor, - devicePropertiesChangedListener) - } - - private fun unregisterReceiver() { - broadcastDispatcher.unregisterReceiver(userSwitcherReceiver) - } - - private fun registerReceiver() { - broadcastDispatcher.registerReceiver(userSwitcherReceiver, IntentFilter().apply { - intents.forEach { - addAction(it) - } - }, null /* handler */, UserHandle.ALL) - } - - private fun update(updateUsers: Boolean) { - if (updateUsers) { - val currentUser = ActivityManager.getCurrentUser() - currentUserIds = userManager.getProfiles(currentUser).map { it.id } - } - bgHandler.post(updateListAndNotifyChanges) - } - - /** - * Updates listening status based on whether there are callbacks and the indicators are enabled - * - * This is only called from private (add/remove)Callback and from the config listener, all in - * main thread. - */ - private fun setListeningState() { - val listen = !callbacks.isEmpty() and indicatorsAvailable - if (listening == listen) return - listening = listen - if (listening) { - appOpsController.addCallback(OPS, cb) - registerReceiver() - update(true) - } else { - appOpsController.removeCallback(OPS, cb) - unregisterReceiver() - // Make sure that we remove all indicators and notify listeners if we are not - // listening anymore due to indicators being disabled - update(false) - } - } - - private fun addCallback(callback: WeakReference) { - callbacks.add(callback) - if (callbacks.isNotEmpty() && !listening) { - messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE) - messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE) - } - // Notify this callback if we didn't set to listening - else if (listening) uiHandler.post(NotifyChangesToCallback(callback.get(), privacyList)) - } - - private fun removeCallback(callback: WeakReference) { - // Removes also if the callback is null - callbacks.removeIf { it.get()?.equals(callback.get()) ?: true } - if (callbacks.isEmpty()) { - messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE) - messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE) - } - } - - fun addCallback(callback: Callback) { - messageHandler.obtainMessage(MSG_ADD_CALLBACK, callback).sendToTarget() - } - - fun removeCallback(callback: Callback) { - messageHandler.obtainMessage(MSG_REMOVE_CALLBACK, callback).sendToTarget() - } - - private fun updatePrivacyList() { - if (!listening) { - privacyList = emptyList() - return - } - val list = currentUserIds.flatMap { appOpsController.getActiveAppOpsForUser(it) } - .mapNotNull { toPrivacyItem(it) }.distinct() - privacyList = list - } - - private fun toPrivacyItem(appOpItem: AppOpItem): PrivacyItem? { - val type: PrivacyType = when (appOpItem.code) { - AppOpsManager.OP_CAMERA -> PrivacyType.TYPE_CAMERA - AppOpsManager.OP_COARSE_LOCATION -> PrivacyType.TYPE_LOCATION - AppOpsManager.OP_FINE_LOCATION -> PrivacyType.TYPE_LOCATION - AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE - else -> return null - } - if (appOpItem.uid == SYSTEM_UID) return PrivacyItem(type, systemApp) - val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid, context) - return PrivacyItem(type, app) - } - - // Used by containing class to get notified of changes - interface Callback { - fun privacyChanged(privacyItems: List) - } - - internal inner class Receiver : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - if (intent?.action in intents) { - update(true) - } - } - } - - private class NotifyChangesToCallback( - private val callback: Callback?, - private val list: List - ) : Runnable { - override fun run() { - callback?.privacyChanged(list) - } - } - - override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array) { - pw.println("PrivacyItemController state:") - pw.println(" Listening: $listening") - pw.println(" Current user ids: $currentUserIds") - pw.println(" Privacy Items:") - privacyList.forEach { - pw.print(" ") - pw.println(it.toString()) - } - pw.println(" Callbacks:") - callbacks.forEach { - it.get()?.let { - pw.print(" ") - pw.println(it.toString()) - } - } - } - - private class H( - private val outerClass: WeakReference, - looper: Looper - ) : Handler(looper) { - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - when (msg.what) { - MSG_UPDATE_LISTENING_STATE -> outerClass.get()?.setListeningState() - - MSG_ADD_CALLBACK -> { - if (msg.obj !is PrivacyItemController.Callback) return - outerClass.get()?.addCallback( - WeakReference(msg.obj as PrivacyItemController.Callback)) - } - - MSG_REMOVE_CALLBACK -> { - if (msg.obj !is PrivacyItemController.Callback) return - outerClass.get()?.removeCallback( - WeakReference(msg.obj as PrivacyItemController.Callback)) - } - else -> {} - } - } - } -} \ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 02e8f59097939..e5cec878b63de 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -33,30 +33,24 @@ import android.graphics.Color; import android.graphics.Rect; import android.media.AudioManager; import android.os.Handler; -import android.os.Looper; import android.provider.AlarmClock; -import android.provider.DeviceConfig; import android.provider.Settings; import android.service.notification.ZenModeConfig; import android.text.format.DateUtils; import android.util.AttributeSet; import android.util.Log; import android.util.Pair; -import android.util.StatsLog; import android.view.ContextThemeWrapper; import android.view.DisplayCutout; import android.view.View; import android.view.WindowInsets; import android.widget.FrameLayout; import android.widget.ImageView; -import android.widget.LinearLayout; import android.widget.RelativeLayout; -import android.widget.Space; import android.widget.TextView; import androidx.annotation.VisibleForTesting; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.settingslib.Utils; import com.android.systemui.BatteryMeterView; import com.android.systemui.DualToneHandler; @@ -65,11 +59,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher; 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.PrivacyDialogBuilder; -import com.android.systemui.privacy.PrivacyItem; -import com.android.systemui.privacy.PrivacyItemController; -import com.android.systemui.privacy.PrivacyItemControllerKt; import com.android.systemui.qs.QSDetail.Callback; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.phone.PhoneStatusBarView; @@ -145,12 +134,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements private View mRingerContainer; private Clock mClockView; private DateView mDateView; - private OngoingPrivacyChip mPrivacyChip; - private Space mSpace; private BatteryMeterView mBatteryRemainingIcon; - private boolean mPermissionsHubEnabled; - private PrivacyItemController mPrivacyItemController; private BroadcastDispatcher mBroadcastDispatcher; private final BroadcastReceiver mRingerReceiver = new BroadcastReceiver() { @@ -161,43 +146,18 @@ public class QuickStatusBarHeader extends RelativeLayout implements } }; private boolean mHasTopCutout = false; - private boolean mPrivacyChipLogged = false; - - private final DeviceConfig.OnPropertiesChangedListener mPropertiesListener = - new DeviceConfig.OnPropertiesChangedListener() { - @Override - public void onPropertiesChanged(DeviceConfig.Properties properties) { - if (DeviceConfig.NAMESPACE_PRIVACY.equals(properties.getNamespace()) - && properties.getKeyset() - .contains(SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED)) { - mPermissionsHubEnabled = properties.getBoolean( - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false); - StatusIconContainer iconContainer = findViewById(R.id.statusIcons); - iconContainer.setIgnoredSlots(getIgnoredIconSlots()); - } - } - }; - - private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() { - @Override - public void privacyChanged(List privacyItems) { - mPrivacyChip.setPrivacyList(privacyItems); - setChipVisibility(!privacyItems.isEmpty()); - } - }; @Inject public QuickStatusBarHeader(@Named(VIEW_CONTEXT) Context context, AttributeSet attrs, NextAlarmController nextAlarmController, ZenModeController zenModeController, StatusBarIconController statusBarIconController, - ActivityStarter activityStarter, PrivacyItemController privacyItemController, + ActivityStarter activityStarter, CommandQueue commandQueue, BroadcastDispatcher broadcastDispatcher) { super(context, attrs); mAlarmController = nextAlarmController; mZenController = zenModeController; mStatusBarIconController = statusBarIconController; mActivityStarter = activityStarter; - mPrivacyItemController = privacyItemController; mDualToneHandler = new DualToneHandler( new ContextThemeWrapper(context, R.style.QSHeaderTheme)); mBroadcastDispatcher = broadcastDispatcher; @@ -228,11 +188,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements mRingerModeTextView = findViewById(R.id.ringer_mode_text); mRingerContainer = findViewById(R.id.ringer_container); mRingerContainer.setOnClickListener(this::onClick); - mPrivacyChip = findViewById(R.id.privacy_chip); - mPrivacyChip.setOnClickListener(this::onClick); mCarrierGroup = findViewById(R.id.carrier_group); - updateResources(); Rect tintArea = new Rect(0, 0, 0, 0); @@ -252,7 +209,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mClockView = findViewById(R.id.clock); mClockView.setOnClickListener(this); mDateView = findViewById(R.id.date); - mSpace = findViewById(R.id.space); // Tint for the battery icons are handled in setupHost() mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon); @@ -263,8 +219,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE); mRingerModeTextView.setSelected(true); mNextAlarmTextView.setSelected(true); - - mPermissionsHubEnabled = PrivacyItemControllerKt.isPermissionsHubEnabled(); } private List getIgnoredIconSlots() { @@ -273,10 +227,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements com.android.internal.R.string.status_bar_camera)); ignored.add(mContext.getResources().getString( com.android.internal.R.string.status_bar_microphone)); - if (mPermissionsHubEnabled) { - ignored.add(mContext.getResources().getString( - com.android.internal.R.string.status_bar_location)); - } return ignored; } @@ -292,21 +242,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements } } - private void setChipVisibility(boolean chipVisible) { - if (chipVisible && mPermissionsHubEnabled) { - mPrivacyChip.setVisibility(View.VISIBLE); - // Makes sure that the chip is logged as viewed at most once each time QS is opened - // mListening makes sure that the callback didn't return after the user closed QS - if (!mPrivacyChipLogged && mListening) { - mPrivacyChipLogged = true; - StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, - StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_VIEWED); - } - } else { - mPrivacyChip.setVisibility(View.GONE); - } - } - private boolean updateRingerStatus() { boolean isOriginalVisible = mRingerModeTextView.getVisibility() == View.VISIBLE; CharSequence originalRingerText = mRingerModeTextView.getText(); @@ -418,7 +353,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements updateStatusIconAlphaAnimator(); updateHeaderTextContainerAlphaAnimator(); - updatePrivacyChipAlphaAnimator(); } private void updateStatusIconAlphaAnimator() { @@ -433,12 +367,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements .build(); } - private void updatePrivacyChipAlphaAnimator() { - mPrivacyChipAlphaAnimator = new TouchAnimator.Builder() - .addFloat(mPrivacyChip, "alpha", 1, 0, 1) - .build(); - } - public void setExpanded(boolean expanded) { if (mExpanded == expanded) return; mExpanded = expanded; @@ -477,10 +405,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mHeaderTextContainerView.setVisibility(INVISIBLE); } } - if (mPrivacyChipAlphaAnimator != null) { - mPrivacyChip.setExpanded(expansionFraction > 0.5); - mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction); - } } public void disable(int state1, int state2, boolean animate) { @@ -498,9 +422,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements super.onAttachedToWindow(); mStatusBarIconController.addIconGroup(mIconManager); requestApplyInsets(); - // Change the ignored slots when DeviceConfig flag changes - DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_PRIVACY, - mContext.getMainExecutor(), mPropertiesListener); } @Override @@ -516,21 +437,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mSystemIconsView.setPadding(padding.first, 0, padding.second, 0); } - LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mSpace.getLayoutParams(); - if (cutout != null) { - Rect topCutout = cutout.getBoundingRectTop(); - if (topCutout.isEmpty()) { - mHasTopCutout = false; - lp.width = 0; - mSpace.setVisibility(View.GONE); - } else { - mHasTopCutout = true; - lp.width = topCutout.width(); - mSpace.setVisibility(View.VISIBLE); - } - } - mSpace.setLayoutParams(lp); - setChipVisibility(mPrivacyChip.getVisibility() == View.VISIBLE); return super.onApplyWindowInsets(insets); } @@ -539,7 +445,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements public void onDetachedFromWindow() { setListening(false); mStatusBarIconController.removeIconGroup(mIconManager); - DeviceConfig.removeOnPropertiesChangedListener(mPropertiesListener); super.onDetachedFromWindow(); } @@ -555,13 +460,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements mAlarmController.addCallback(this); mBroadcastDispatcher.registerReceiver(mRingerReceiver, new IntentFilter(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)); - mPrivacyItemController.addCallback(mPICCallback); } else { mZenController.removeCallback(this); mAlarmController.removeCallback(this); - mPrivacyItemController.removeCallback(mPICCallback); mBroadcastDispatcher.unregisterReceiver(mRingerReceiver); - mPrivacyChipLogged = false; } } @@ -579,18 +481,6 @@ public class QuickStatusBarHeader extends RelativeLayout implements mActivityStarter.postStartActivityDismissingKeyguard(new Intent( AlarmClock.ACTION_SHOW_ALARMS), 0); } - } else if (v == mPrivacyChip) { - // Makes sure that the builder is grabbed as soon as the chip is pressed - PrivacyDialogBuilder builder = mPrivacyChip.getBuilder(); - if (builder.getAppsAndTypes().size() == 0) return; - Handler mUiHandler = new Handler(Looper.getMainLooper()); - StatsLog.write(StatsLog.PRIVACY_INDICATORS_INTERACTED, - StatsLog.PRIVACY_INDICATORS_INTERACTED__TYPE__CHIP_CLICKED); - mUiHandler.post(() -> { - mActivityStarter.postStartActivityDismissingKeyguard( - new Intent(Intent.ACTION_REVIEW_ONGOING_PERMISSION_USAGE), 0); - mHost.collapsePanels(); - }); } else if (v == mRingerContainer && mRingerContainer.isVisibleToUser()) { mActivityStarter.postStartActivityDismissingKeyguard(new Intent( Settings.ACTION_SOUND_SETTINGS), 0); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index bfecaaab46b98..8d43c6666773b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -43,10 +43,6 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.UiOffloadThread; import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.privacy.PrivacyItem; -import com.android.systemui.privacy.PrivacyItemController; -import com.android.systemui.privacy.PrivacyItemControllerKt; -import com.android.systemui.privacy.PrivacyType; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.statusbar.CommandQueue; @@ -67,9 +63,6 @@ import com.android.systemui.statusbar.policy.SensorPrivacyController; import com.android.systemui.statusbar.policy.UserInfoController; import com.android.systemui.statusbar.policy.ZenModeController; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.List; import java.util.Locale; /** @@ -84,12 +77,12 @@ public class PhoneStatusBarPolicy ZenModeController.Callback, DeviceProvisionedListener, KeyguardStateController.Callback, - PrivacyItemController.Callback, LocationController.LocationChangeCallback { private static final String TAG = "PhoneStatusBarPolicy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - public static final int LOCATION_STATUS_ICON_ID = PrivacyType.TYPE_LOCATION.getIconId(); + public static final int LOCATION_STATUS_ICON_ID = + com.android.internal.R.drawable.perm_group_location; private final String mSlotCast; private final String mSlotHotspot; @@ -122,7 +115,6 @@ public class PhoneStatusBarPolicy private final DeviceProvisionedController mProvisionedController; private final KeyguardStateController mKeyguardStateController; private final LocationController mLocationController; - private final PrivacyItemController mPrivacyItemController; private final UiOffloadThread mUiOffloadThread = Dependency.get(UiOffloadThread.class); private final SensorPrivacyController mSensorPrivacyController; @@ -156,7 +148,6 @@ public class PhoneStatusBarPolicy mProvisionedController = Dependency.get(DeviceProvisionedController.class); mKeyguardStateController = Dependency.get(KeyguardStateController.class); mLocationController = Dependency.get(LocationController.class); - mPrivacyItemController = Dependency.get(PrivacyItemController.class); mSensorPrivacyController = Dependency.get(SensorPrivacyController.class); mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast); @@ -233,13 +224,6 @@ public class PhoneStatusBarPolicy context.getString(R.string.accessibility_data_saver_on)); mIconController.setIconVisibility(mSlotDataSaver, false); - // privacy items - mIconController.setIcon(mSlotMicrophone, PrivacyType.TYPE_MICROPHONE.getIconId(), - PrivacyType.TYPE_MICROPHONE.getName(mContext)); - mIconController.setIconVisibility(mSlotMicrophone, false); - mIconController.setIcon(mSlotCamera, PrivacyType.TYPE_CAMERA.getIconId(), - PrivacyType.TYPE_CAMERA.getName(mContext)); - mIconController.setIconVisibility(mSlotCamera, false); mIconController.setIcon(mSlotLocation, LOCATION_STATUS_ICON_ID, mContext.getString(R.string.accessibility_location_active)); mIconController.setIconVisibility(mSlotLocation, false); @@ -259,7 +243,6 @@ public class PhoneStatusBarPolicy mNextAlarmController.addCallback(mNextAlarmCallback); mDataSaver.addCallback(this); mKeyguardStateController.addCallback(this); - mPrivacyItemController.addCallback(this); mSensorPrivacyController.addCallback(mSensorPrivacyListener); mLocationController.addCallback(this); @@ -603,46 +586,9 @@ public class PhoneStatusBarPolicy mIconController.setIconVisibility(mSlotDataSaver, isDataSaving); } - @Override // PrivacyItemController.Callback - public void privacyChanged(List privacyItems) { - updatePrivacyItems(privacyItems); - } - - private void updatePrivacyItems(List items) { - boolean showCamera = false; - boolean showMicrophone = false; - boolean showLocation = false; - for (PrivacyItem item : items) { - if (item == null /* b/124234367 */) { - if (DEBUG) { - Log.e(TAG, "updatePrivacyItems - null item found"); - StringWriter out = new StringWriter(); - mPrivacyItemController.dump(null, new PrintWriter(out), null); - Log.e(TAG, out.toString()); - } - continue; - } - switch (item.getPrivacyType()) { - case TYPE_CAMERA: - showCamera = true; - break; - case TYPE_LOCATION: - showLocation = true; - break; - case TYPE_MICROPHONE: - showMicrophone = true; - break; - } - } - - mIconController.setIconVisibility(mSlotCamera, showCamera); - mIconController.setIconVisibility(mSlotMicrophone, showMicrophone); - mIconController.setIconVisibility(mSlotLocation, showLocation); - } - @Override public void onLocationActiveChanged(boolean active) { - if (!PrivacyItemControllerKt.isPermissionsHubEnabled()) updateLocation(); + updateLocation(); } // Updates the status view based on the current state of location requests. diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt deleted file mode 100644 index 6302f9d56dc3f..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyDialogBuilderTest.kt +++ /dev/null @@ -1,77 +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 androidx.test.filters.SmallTest -import androidx.test.runner.AndroidJUnit4 -import com.android.systemui.SysuiTestCase -import org.junit.Assert.assertEquals -import org.junit.Test -import org.junit.runner.RunWith - -@RunWith(AndroidJUnit4::class) -@SmallTest -class PrivacyDialogBuilderTest : SysuiTestCase() { - - companion object { - val TEST_UID = 1 - } - - @Test - fun testGenerateAppsList() { - val bar2 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( - "Bar", TEST_UID, context)) - val bar3 = PrivacyItem(Privacy.TYPE_LOCATION, PrivacyApplication( - "Bar", TEST_UID, context)) - val foo0 = PrivacyItem(Privacy.TYPE_MICROPHONE, PrivacyApplication( - "Foo", TEST_UID, context)) - val baz1 = PrivacyItem(Privacy.TYPE_CAMERA, PrivacyApplication( - "Baz", TEST_UID, context)) - - val items = listOf(bar2, foo0, baz1, bar3) - - val textBuilder = PrivacyDialogBuilder(context, items) - - val list = textBuilder.appsAndTypes - assertEquals(3, list.size) - val appsList = list.map { it.first } - val typesList = list.map { it.second } - // List is sorted by number of types and then by types - assertEquals(listOf("Bar", "Baz", "Foo"), appsList.map { it.packageName }) - assertEquals(listOf(Privacy.TYPE_CAMERA, Privacy.TYPE_LOCATION), typesList[0]) - assertEquals(listOf(Privacy.TYPE_CAMERA), typesList[1]) - assertEquals(listOf(Privacy.TYPE_MICROPHONE), typesList[2]) - } - - @Test - fun testOrder() { - // We want location to always go last, so it will go in the "+ other apps" - val appCamera = PrivacyItem(PrivacyType.TYPE_CAMERA, - PrivacyApplication("Camera", TEST_UID, context)) - val appMicrophone = - PrivacyItem(PrivacyType.TYPE_MICROPHONE, - PrivacyApplication("Microphone", TEST_UID, context)) - val appLocation = - PrivacyItem(PrivacyType.TYPE_LOCATION, - PrivacyApplication("Location", TEST_UID, context)) - - val items = listOf(appLocation, appMicrophone, appCamera) - val textBuilder = PrivacyDialogBuilder(context, items) - val appList = textBuilder.appsAndTypes.map { it.first }.map { it.packageName } - assertEquals(listOf("Camera", "Microphone", "Location"), appList) - } -} \ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt deleted file mode 100644 index 20148e11489a6..0000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt +++ /dev/null @@ -1,315 +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.ActivityManager -import android.app.AppOpsManager -import android.content.Context -import android.content.Intent -import android.content.pm.UserInfo -import android.os.Handler -import android.os.UserHandle -import android.os.UserManager -import android.provider.DeviceConfig -import android.provider.Settings.RESET_MODE_PACKAGE_DEFAULTS -import android.testing.AndroidTestingRunner -import android.testing.TestableLooper -import android.testing.TestableLooper.RunWithLooper -import androidx.test.filters.SmallTest -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags -import com.android.systemui.Dependency -import com.android.systemui.R -import com.android.systemui.SysuiTestCase -import com.android.systemui.appops.AppOpItem -import com.android.systemui.appops.AppOpsController -import com.android.systemui.broadcast.BroadcastDispatcher -import org.hamcrest.Matchers.hasItem -import org.hamcrest.Matchers.not -import org.hamcrest.Matchers.nullValue -import org.junit.After -import org.junit.Assert.assertEquals -import org.junit.Assert.assertThat -import org.junit.Assert.assertTrue -import org.junit.Before -import org.junit.Ignore -import org.junit.Test -import org.junit.runner.RunWith -import org.mockito.ArgumentCaptor -import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt -import org.mockito.ArgumentMatchers.anyList -import org.mockito.ArgumentMatchers.anyString -import org.mockito.ArgumentMatchers.eq -import org.mockito.Captor -import org.mockito.Mock -import org.mockito.Mockito.atLeastOnce -import org.mockito.Mockito.doAnswer -import org.mockito.Mockito.doReturn -import org.mockito.Mockito.mock -import org.mockito.Mockito.never -import org.mockito.Mockito.reset -import org.mockito.Mockito.verify -import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.MockitoAnnotations - -@RunWith(AndroidTestingRunner::class) -@SmallTest -@RunWithLooper -@Ignore -class PrivacyItemControllerTest : SysuiTestCase() { - - companion object { - val CURRENT_USER_ID = ActivityManager.getCurrentUser() - val TEST_UID = CURRENT_USER_ID * UserHandle.PER_USER_RANGE - const val SYSTEM_UID = 1000 - const val TEST_PACKAGE_NAME = "test" - const val DEVICE_SERVICES_STRING = "Device services" - const val TAG = "PrivacyItemControllerTest" - fun capture(argumentCaptor: ArgumentCaptor): T = argumentCaptor.capture() - } - - @Mock - private lateinit var appOpsController: AppOpsController - @Mock - private lateinit var callback: PrivacyItemController.Callback - @Mock - private lateinit var userManager: UserManager - @Mock - private lateinit var broadcastDispatcher: BroadcastDispatcher - @Captor - private lateinit var argCaptor: ArgumentCaptor> - @Captor - private lateinit var argCaptorCallback: ArgumentCaptor - - private lateinit var testableLooper: TestableLooper - private lateinit var privacyItemController: PrivacyItemController - private lateinit var handler: Handler - - fun PrivacyItemController(context: Context) = - PrivacyItemController(context, appOpsController, handler, handler, broadcastDispatcher) - - @Before - fun setup() { - MockitoAnnotations.initMocks(this) - testableLooper = TestableLooper.get(this) - handler = Handler(testableLooper.looper) - - appOpsController = mDependency.injectMockDependency(AppOpsController::class.java) - mDependency.injectTestDependency(Dependency.MAIN_HANDLER, handler) - mContext.addMockSystemService(UserManager::class.java, userManager) - mContext.getOrCreateTestableResources().addOverride(R.string.device_services, - DEVICE_SERVICES_STRING) - DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, - "true", false) - - doReturn(listOf(object : UserInfo() { - init { - id = CURRENT_USER_ID - } - })).`when`(userManager).getProfiles(anyInt()) - - privacyItemController = PrivacyItemController(mContext) - } - - @After - fun tearDown() { - DeviceConfig.resetToDefaults(RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.NAMESPACE_PRIVACY) - } - - @Test - fun testSetListeningTrueByAddingCallback() { - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - verify(appOpsController).addCallback(eq(PrivacyItemController.OPS), - any(AppOpsController.Callback::class.java)) - testableLooper.processAllMessages() - verify(callback).privacyChanged(anyList()) - } - - @Test - fun testSetListeningFalseByRemovingLastCallback() { - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - verify(appOpsController, never()).removeCallback(any(IntArray::class.java), - any(AppOpsController.Callback::class.java)) - privacyItemController.removeCallback(callback) - testableLooper.processAllMessages() - verify(appOpsController).removeCallback(eq(PrivacyItemController.OPS), - any(AppOpsController.Callback::class.java)) - verify(callback).privacyChanged(emptyList()) - } - - @Test - fun testDistinctItems() { - doReturn(listOf(AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 0), - AppOpItem(AppOpsManager.OP_CAMERA, TEST_UID, "", 1))) - .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) - - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - verify(callback).privacyChanged(capture(argCaptor)) - assertEquals(1, argCaptor.value.size) - } - - @Test - fun testSystemApps() { - doReturn(listOf(AppOpItem(AppOpsManager.OP_COARSE_LOCATION, SYSTEM_UID, TEST_PACKAGE_NAME, - 0))).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - verify(callback).privacyChanged(capture(argCaptor)) - assertEquals(1, argCaptor.value.size) - assertEquals(context.getString(R.string.device_services), - argCaptor.value[0].application.applicationName) - } - - @Test - fun testRegisterReceiver_allUsers() { - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - verify(broadcastDispatcher, atLeastOnce()).registerReceiver( - eq(privacyItemController.userSwitcherReceiver), any(), eq(null), eq(UserHandle.ALL)) - verify(broadcastDispatcher, never()) - .unregisterReceiver(eq(privacyItemController.userSwitcherReceiver)) - } - - @Test - fun testReceiver_ACTION_USER_FOREGROUND() { - privacyItemController.userSwitcherReceiver.onReceive(context, - Intent(Intent.ACTION_USER_FOREGROUND)) - verify(userManager).getProfiles(anyInt()) - } - - @Test - fun testReceiver_ACTION_MANAGED_PROFILE_ADDED() { - privacyItemController.userSwitcherReceiver.onReceive(context, - Intent(Intent.ACTION_MANAGED_PROFILE_ADDED)) - verify(userManager).getProfiles(anyInt()) - } - - @Test - fun testReceiver_ACTION_MANAGED_PROFILE_REMOVED() { - privacyItemController.userSwitcherReceiver.onReceive(context, - Intent(Intent.ACTION_MANAGED_PROFILE_REMOVED)) - verify(userManager).getProfiles(anyInt()) - } - - @Test - fun testAddMultipleCallbacks() { - val otherCallback = mock(PrivacyItemController.Callback::class.java) - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - verify(callback).privacyChanged(anyList()) - - privacyItemController.addCallback(otherCallback) - testableLooper.processAllMessages() - verify(otherCallback).privacyChanged(anyList()) - // Adding a callback should not unnecessarily call previous ones - verifyNoMoreInteractions(callback) - } - - @Test - fun testMultipleCallbacksAreUpdated() { - doReturn(emptyList()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) - - val otherCallback = mock(PrivacyItemController.Callback::class.java) - privacyItemController.addCallback(callback) - privacyItemController.addCallback(otherCallback) - testableLooper.processAllMessages() - reset(callback) - reset(otherCallback) - - verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) - argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true) - testableLooper.processAllMessages() - verify(callback).privacyChanged(anyList()) - verify(otherCallback).privacyChanged(anyList()) - } - - @Test - fun testRemoveCallback() { - doReturn(emptyList()).`when`(appOpsController).getActiveAppOpsForUser(anyInt()) - val otherCallback = mock(PrivacyItemController.Callback::class.java) - privacyItemController.addCallback(callback) - privacyItemController.addCallback(otherCallback) - testableLooper.processAllMessages() - reset(callback) - reset(otherCallback) - - verify(appOpsController).addCallback(any(), capture(argCaptorCallback)) - privacyItemController.removeCallback(callback) - argCaptorCallback.value.onActiveStateChanged(0, TEST_UID, "", true) - testableLooper.processAllMessages() - verify(callback, never()).privacyChanged(anyList()) - verify(otherCallback).privacyChanged(anyList()) - } - - @Test - fun testListShouldNotHaveNull() { - doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0), - AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0))) - .`when`(appOpsController).getActiveAppOpsForUser(anyInt()) - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - - verify(callback).privacyChanged(capture(argCaptor)) - assertEquals(1, argCaptor.value.size) - assertThat(argCaptor.value, not(hasItem(nullValue()))) - } - - @Test - fun testListShouldBeCopy() { - val list = listOf(PrivacyItem(PrivacyType.TYPE_CAMERA, - PrivacyApplication("", TEST_UID, mContext))) - privacyItemController.privacyList = list - val privacyList = privacyItemController.privacyList - assertEquals(list, privacyList) - assertTrue(list !== privacyList) - } - - @Test - fun testNotListeningWhenIndicatorsDisabled() { - val properties = getProperties( - DeviceConfig.NAMESPACE_PRIVACY, - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, - false) - privacyItemController.devicePropertiesChangedListener.onPropertiesChanged(properties) - privacyItemController.addCallback(callback) - testableLooper.processAllMessages() - verify(appOpsController, never()).addCallback(eq(PrivacyItemController.OPS), - any(AppOpsController.Callback::class.java)) - } - - private fun getProperties(namespace: String, name: String, value: Boolean): - DeviceConfig.Properties { - val properties = mock(DeviceConfig.Properties::class.java) - doReturn(namespace).`when`(properties).getNamespace() - doReturn(setOf(name)).`when`(properties).getKeyset() - doAnswer { - val key: String = it.getArgument(0) - val defaultValue: Boolean = it.getArgument(1) - if (name.equals(key, ignoreCase = true)) { - value - } else { - defaultValue - } - }.`when`(properties).getBoolean(anyString(), anyBoolean()) - return properties - } -} \ No newline at end of file diff --git a/services/core/java/com/android/server/appop/HistoricalRegistry.java b/services/core/java/com/android/server/appop/HistoricalRegistry.java index 5983785d42470..2175ca0362b0f 100644 --- a/services/core/java/com/android/server/appop/HistoricalRegistry.java +++ b/services/core/java/com/android/server/appop/HistoricalRegistry.java @@ -46,7 +46,6 @@ import android.util.TimeUtils; import android.util.Xml; import com.android.internal.annotations.GuardedBy; -import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; import com.android.internal.os.AtomicDirectory; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; @@ -128,6 +127,7 @@ final class HistoricalRegistry { private static final String PARAMETER_DELIMITER = ","; private static final String PARAMETER_ASSIGNMENT = "="; + private static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; @GuardedBy("mLock") private @NonNull LinkedList mPendingWrites = new LinkedList<>(); @@ -701,7 +701,7 @@ final class HistoricalRegistry { private static boolean isApiEnabled() { return Binder.getCallingUid() == Process.myUid() || DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, - SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false); + PROPERTY_PERMISSIONS_HUB_ENABLED, false); } private static final class Persistence {