Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70f3600c authored by Fabian Kozynski's avatar Fabian Kozynski Committed by Android (Google) Code Review
Browse files

Merge "Separate mic + camera from location"

parents fc0f15dc 2fb81031
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -123,10 +123,15 @@ public final class SystemUiDeviceConfigFlags {
    // Flag related to Privacy Indicators

    /**
     * Whether the Permissions Hub is showing.
     * Whether to show the complete ongoing app ops chip.
     */
    public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_2_enabled";

    /**
     * Whether to show app ops chip for just microphone + camera.
     */
    public static final String PROPERTY_MIC_CAMERA_ENABLED = "camera_mic_icons_enabled";

    // Flags related to Assistant

    /**
+5 −3
Original line number Diff line number Diff line
@@ -281,9 +281,11 @@ public class AppOpsControllerImpl implements AppOpsController,
     * @return {@code true} iff the app-op for should be shown to the user
     */
    private boolean isUserVisible(int appOpCode, int uid, String packageName) {
        // currently OP_SYSTEM_ALERT_WINDOW does not correspond to a platform permission
        // which may be user senstive, so for now always show it to the user.
        if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW) {
        // currently OP_SYSTEM_ALERT_WINDOW and OP_MONITOR_HIGH_POWER_LOCATION
        // does not correspond to a platform permission
        // which may be user sensitive, so for now always show it to the user.
        if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW
                || appOpCode == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
            return true;
        }

+45 −19
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import javax.inject.Singleton

@Singleton
class PrivacyItemController @Inject constructor(
    context: Context,
    private val appOpsController: AppOpsController,
    @Main uiExecutor: DelayableExecutor,
    @Background private val bgExecutor: Executor,
@@ -57,16 +56,21 @@ class PrivacyItemController @Inject constructor(

    @VisibleForTesting
    internal companion object {
        val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
                AppOpsManager.OP_RECORD_AUDIO,
        val OPS_MIC_CAMERA = intArrayOf(AppOpsManager.OP_CAMERA,
                AppOpsManager.OP_RECORD_AUDIO)
        val OPS_LOCATION = intArrayOf(
                AppOpsManager.OP_COARSE_LOCATION,
                AppOpsManager.OP_FINE_LOCATION)
        val OPS = OPS_MIC_CAMERA + OPS_LOCATION
        val intentFilter = IntentFilter().apply {
            addAction(Intent.ACTION_USER_SWITCHED)
            addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE)
            addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)
        }
        const val TAG = "PrivacyItemController"
        private const val ALL_INDICATORS =
                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED
        private const val MIC_CAMERA = SystemUiDeviceConfigFlags.PROPERTY_MIC_CAMERA_ENABLED
    }

    @VisibleForTesting
@@ -74,9 +78,14 @@ class PrivacyItemController @Inject constructor(
        @Synchronized get() = field.toList() // Returns a shallow copy of the list
        @Synchronized set

    private fun isPermissionsHubEnabled(): Boolean {
    private fun isAllIndicatorsEnabled(): Boolean {
        return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
                ALL_INDICATORS, false)
    }

    private fun isMicCameraEnabled(): Boolean {
        return deviceConfigProxy.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                MIC_CAMERA, false)
    }

    private var currentUserIds = emptyList<Int>()
@@ -94,23 +103,28 @@ class PrivacyItemController @Inject constructor(
        uiExecutor.execute(notifyChanges)
    }

    var indicatorsAvailable = isPermissionsHubEnabled()
    var allIndicatorsAvailable = isAllIndicatorsEnabled()
        private set
    @VisibleForTesting
    internal val devicePropertiesChangedListener =
    var micCameraAvailable = isMicCameraEnabled()
        private set

    private 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)) {
                val flag = properties.getBoolean(
                        SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)
                if (indicatorsAvailable != flag) {
                    // This is happening already in the UI executor, so we can iterate in the
                    indicatorsAvailable = flag
                    callbacks.forEach { it.get()?.onFlagChanged(flag) }
                    (properties.keyset.contains(ALL_INDICATORS) ||
                    properties.keyset.contains(MIC_CAMERA))) {

                // Running on the ui executor so can iterate on callbacks
                if (properties.keyset.contains(ALL_INDICATORS)) {
                    allIndicatorsAvailable = properties.getBoolean(ALL_INDICATORS, false)
                    callbacks.forEach { it.get()?.onFlagAllChanged(allIndicatorsAvailable) }
                }

                if (properties.keyset.contains(MIC_CAMERA)) {
                    micCameraAvailable = properties.getBoolean(MIC_CAMERA, false)
                    callbacks.forEach { it.get()?.onFlagMicCameraChanged(micCameraAvailable) }
                }
                internalUiExecutor.updateListeningState()
            }
        }
@@ -123,6 +137,10 @@ class PrivacyItemController @Inject constructor(
            packageName: String,
            active: Boolean
        ) {
            // Check if we care about this code right now
            if (!allIndicatorsAvailable && code in OPS_LOCATION) {
                return
            }
            val userId = UserHandle.getUserId(uid)
            if (userId in currentUserIds) {
                update(false)
@@ -166,13 +184,16 @@ class PrivacyItemController @Inject constructor(
    }

    /**
     * Updates listening status based on whether there are callbacks and the indicators are enabled
     * Updates listening status based on whether there are callbacks and the indicators are enabled.
     *
     * Always listen to all OPS so we don't have to figure out what we should be listening to. We
     * still have to filter anyway. Updates are filtered in the callback.
     *
     * 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
        val listen = !callbacks.isEmpty() and (allIndicatorsAvailable || micCameraAvailable)
        if (listening == listen) return
        listening = listen
        if (listening) {
@@ -233,14 +254,19 @@ class PrivacyItemController @Inject constructor(
            AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE
            else -> return null
        }
        if (type == PrivacyType.TYPE_LOCATION && !allIndicatorsAvailable) return null
        val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid)
        return PrivacyItem(type, app)
    }

    interface Callback {
        fun onPrivacyItemsChanged(privacyItems: List<PrivacyItem>)

        @JvmDefault
        fun onFlagAllChanged(flag: Boolean) {}

        @JvmDefault
        fun onFlagChanged(flag: Boolean) {}
        fun onFlagMicCameraChanged(flag: Boolean) {}
    }

    internal inner class Receiver : BroadcastReceiver() {
+37 −15
Original line number Diff line number Diff line
@@ -151,7 +151,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
    private Space mSpace;
    private BatteryMeterView mBatteryRemainingIcon;
    private RingerModeTracker mRingerModeTracker;
    private boolean mPermissionsHubEnabled;
    private boolean mAllIndicatorsEnabled;
    private boolean mMicCameraIndicatorsEnabled;

    private PrivacyItemController mPrivacyItemController;
    private final UiEventLogger mUiEventLogger;
@@ -178,13 +179,26 @@ public class QuickStatusBarHeader extends RelativeLayout implements
        }

        @Override
        public void onFlagChanged(boolean flag) {
            if (mPermissionsHubEnabled != flag) {
        public void onFlagAllChanged(boolean flag) {
            if (mAllIndicatorsEnabled != flag) {
                mAllIndicatorsEnabled = flag;
                update();
            }
        }

        @Override
        public void onFlagMicCameraChanged(boolean flag) {
            if (mMicCameraIndicatorsEnabled != flag) {
                mMicCameraIndicatorsEnabled = flag;
                update();
            }
        }

        private void update() {
            StatusIconContainer iconContainer = requireViewById(R.id.statusIcons);
            iconContainer.setIgnoredSlots(getIgnoredIconSlots());
            setChipVisibility(!mPrivacyChip.getPrivacyList().isEmpty());
        }
        }
    };

    @Inject
@@ -267,7 +281,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
        mRingerModeTextView.setSelected(true);
        mNextAlarmTextView.setSelected(true);

        mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable();
        mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
        mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
    }

    public QuickQSPanel getHeaderQsPanel() {
@@ -276,14 +291,16 @@ public class QuickStatusBarHeader extends RelativeLayout implements

    private List<String> getIgnoredIconSlots() {
        ArrayList<String> ignored = new ArrayList<>();
        if (getChipEnabled()) {
            ignored.add(mContext.getResources().getString(
                    com.android.internal.R.string.status_bar_camera));
            ignored.add(mContext.getResources().getString(
                    com.android.internal.R.string.status_bar_microphone));
        if (mPermissionsHubEnabled) {
            if (mAllIndicatorsEnabled) {
                ignored.add(mContext.getResources().getString(
                        com.android.internal.R.string.status_bar_location));
            }
        }

        return ignored;
    }
@@ -300,7 +317,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
    }

    private void setChipVisibility(boolean chipVisible) {
        if (chipVisible && mPermissionsHubEnabled) {
        if (chipVisible && getChipEnabled()) {
            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
@@ -607,7 +624,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
            mAlarmController.addCallback(this);
            mLifecycle.setCurrentState(Lifecycle.State.RESUMED);
            // Get the most up to date info
            mPermissionsHubEnabled = mPrivacyItemController.getIndicatorsAvailable();
            mAllIndicatorsEnabled = mPrivacyItemController.getAllIndicatorsAvailable();
            mMicCameraIndicatorsEnabled = mPrivacyItemController.getMicCameraAvailable();
            mPrivacyItemController.addCallback(mPICCallback);
        } else {
            mZenController.removeCallback(this);
@@ -747,4 +765,8 @@ public class QuickStatusBarHeader extends RelativeLayout implements
            updateHeaderTextContainerAlphaAnimator();
        }
    }

    private boolean getChipEnabled() {
        return mMicCameraIndicatorsEnabled || mAllIndicatorsEnabled;
    }
}
+5 −3
Original line number Diff line number Diff line
@@ -662,16 +662,18 @@ public class PhoneStatusBarPolicy

        mIconController.setIconVisibility(mSlotCamera, showCamera);
        mIconController.setIconVisibility(mSlotMicrophone, showMicrophone);
        if (mPrivacyItemController.getAllIndicatorsAvailable()) {
            mIconController.setIconVisibility(mSlotLocation, showLocation);
        }
    }

    @Override
    public void onLocationActiveChanged(boolean active) {
        if (!mPrivacyItemController.getIndicatorsAvailable()) updateLocation();
        if (!mPrivacyItemController.getAllIndicatorsAvailable()) updateLocationFromController();
    }

    // Updates the status view based on the current state of location requests.
    private void updateLocation() {
    private void updateLocationFromController() {
        if (mLocationController.isLocationActive()) {
            mIconController.setIconVisibility(mSlotLocation, true);
        } else {
Loading