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

Commit b7b7a684 authored by Fabian Kozynski's avatar Fabian Kozynski Committed by android-build-merger
Browse files

Merge "Add DeviceConfig flags to Privacy Indicators" into qt-dev

am: 9faaa273

Change-Id: Ia6f40680c30ea1271d664173805a7b4fcef4b7f0
parents dda03c67 9faaa273
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -106,5 +106,12 @@ 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";

    private SystemUiDeviceConfigFlags() { }
}
+83 −9
Original line number Diff line number Diff line
@@ -23,9 +23,13 @@ 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.Dependency.BG_HANDLER_NAME
import com.android.systemui.Dependency.MAIN_HANDLER_NAME
import com.android.systemui.R
@@ -39,6 +43,9 @@ import javax.inject.Inject
import javax.inject.Named
import javax.inject.Singleton

fun isPermissionsHubEnabled() = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY,
                SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED, false)

@Singleton
class PrivacyItemController @Inject constructor(
        val context: Context,
@@ -47,7 +54,8 @@ class PrivacyItemController @Inject constructor(
        @Named(BG_HANDLER_NAME) private val bgHandler: Handler
) : Dumpable {

    companion object {
    @VisibleForTesting
    internal companion object {
        val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
                AppOpsManager.OP_RECORD_AUDIO,
                AppOpsManager.OP_COARSE_LOCATION,
@@ -57,6 +65,9 @@ class PrivacyItemController @Inject constructor(
                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
@@ -70,6 +81,7 @@ class PrivacyItemController @Inject constructor(
    val systemApp =
            PrivacyApplication(context.getString(R.string.device_services), SYSTEM_UID, context)
    private val callbacks = mutableListOf<WeakReference<Callback>>()
    private val messageHandler = H(WeakReference(this), uiHandler.looper)

    private val notifyChanges = Runnable {
        val list = privacyList
@@ -81,6 +93,20 @@ class PrivacyItemController @Inject constructor(
        uiHandler.post(notifyChanges)
    }

    private var indicatorsAvailable = isPermissionsHubEnabled()
    @VisibleForTesting
    internal val devicePropertyChangedListener =
            object : DeviceConfig.OnPropertyChangedListener {
        override fun onPropertyChanged(namespace: String, name: String, value: String?) {
            if (DeviceConfig.NAMESPACE_PRIVACY.equals(namespace) &&
                    SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED.equals(name)) {
                indicatorsAvailable = java.lang.Boolean.parseBoolean(value)
                messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE)
                messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE)
            }
        }
    }

    private val cb = object : AppOpsController.Callback {
        override fun onActiveStateChanged(
            code: Int,
@@ -103,6 +129,11 @@ class PrivacyItemController @Inject constructor(
            registerReceiver()
        }

    init {
        DeviceConfig.addOnPropertyChangedListener(
                DeviceConfig.NAMESPACE_PRIVACY, context.mainExecutor, devicePropertyChangedListener)
    }

    private fun unregisterReceiver() {
        context.unregisterReceiver(userSwitcherReceiver)
    }
@@ -123,8 +154,14 @@ class PrivacyItemController @Inject constructor(
        bgHandler.post(updateListAndNotifyChanges)
    }

    @VisibleForTesting
    internal fun setListening(listen: Boolean) {
    /**
     * 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) {
@@ -134,32 +171,44 @@ class PrivacyItemController @Inject constructor(
        } 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<Callback>) {
        callbacks.add(callback)
        if (callbacks.isNotEmpty() && !listening) setListening(true)
        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 uiHandler.post(NotifyChangesToCallback(callback.get(), privacyList))
        else if (listening) uiHandler.post(NotifyChangesToCallback(callback.get(), privacyList))
    }

    private fun removeCallback(callback: WeakReference<Callback>) {
        // Removes also if the callback is null
        callbacks.removeIf { it.get()?.equals(callback.get()) ?: true }
        if (callbacks.isEmpty()) setListening(false)
        if (callbacks.isEmpty()) {
            messageHandler.removeMessages(MSG_UPDATE_LISTENING_STATE)
            messageHandler.sendEmptyMessage(MSG_UPDATE_LISTENING_STATE)
        }
    }

    fun addCallback(callback: Callback) {
        addCallback(WeakReference(callback))
        messageHandler.obtainMessage(MSG_ADD_CALLBACK, callback).sendToTarget()
    }

    fun removeCallback(callback: Callback) {
        removeCallback(WeakReference(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
@@ -217,4 +266,29 @@ class PrivacyItemController @Inject constructor(
            }
        }
    }

    private class H(
            private val outerClass: WeakReference<PrivacyItemController>,
            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
+29 −3
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@ 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;
@@ -54,6 +55,7 @@ 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,6 +67,7 @@ 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.phone.PhoneStatusBarView;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -141,6 +144,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
    private OngoingPrivacyChip mPrivacyChip;
    private Space mSpace;
    private BatteryMeterView mBatteryRemainingIcon;
    private boolean mPermissionsHubEnabled;

    private PrivacyItemController mPrivacyItemController;

@@ -154,6 +158,20 @@ public class QuickStatusBarHeader extends RelativeLayout implements
    private boolean mHasTopCutout = false;
    private boolean mPrivacyChipLogged = false;

    private final DeviceConfig.OnPropertyChangedListener mPropertyListener =
            new DeviceConfig.OnPropertyChangedListener() {
                @Override
                public void onPropertyChanged(String namespace, String name, String value) {
                    if (DeviceConfig.NAMESPACE_PRIVACY.equals(namespace)
                            && SystemUiDeviceConfigFlags.PROPERTY_PERMISSIONS_HUB_ENABLED.equals(
                            name)) {
                        mPermissionsHubEnabled = Boolean.valueOf(value);
                        StatusIconContainer iconContainer = findViewById(R.id.statusIcons);
                        iconContainer.setIgnoredSlots(getIgnoredIconSlots());
                    }
                }
            };

    private PrivacyItemController.Callback mPICCallback = new PrivacyItemController.Callback() {
        @Override
        public void privacyChanged(List<PrivacyItem> privacyItems) {
@@ -236,6 +254,12 @@ public class QuickStatusBarHeader extends RelativeLayout implements
        mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
        mRingerModeTextView.setSelected(true);
        mNextAlarmTextView.setSelected(true);

        mPermissionsHubEnabled = PrivacyItemControllerKt.isPermissionsHubEnabled();
        // Change the ignored slots when DeviceConfig flag changes
        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_PRIVACY,
                mContext.getMainExecutor(), mPropertyListener);

    }

    private List<String> getIgnoredIconSlots() {
@@ -244,8 +268,10 @@ 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;
    }
@@ -262,7 +288,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements
    }

    private void setChipVisibility(boolean chipVisible) {
        if (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
+18 −1
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.systemui.SysUiServiceProvider;
import com.android.systemui.UiOffloadThread;
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;
@@ -82,7 +83,8 @@ public class PhoneStatusBarPolicy
                ZenModeController.Callback,
                DeviceProvisionedListener,
                KeyguardMonitor.Callback,
                PrivacyItemController.Callback {
                PrivacyItemController.Callback,
                LocationController.LocationChangeCallback {
    private static final String TAG = "PhoneStatusBarPolicy";
    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

@@ -257,6 +259,7 @@ public class PhoneStatusBarPolicy
        mKeyguardMonitor.addCallback(this);
        mPrivacyItemController.addCallback(this);
        mSensorPrivacyController.addCallback(mSensorPrivacyListener);
        mLocationController.addCallback(this);

        SysUiServiceProvider.getComponent(mContext, CommandQueue.class).addCallback(this);
    }
@@ -635,6 +638,20 @@ public class PhoneStatusBarPolicy
        mIconController.setIconVisibility(mSlotLocation, showLocation);
    }

    @Override
    public void onLocationActiveChanged(boolean active) {
        if (!PrivacyItemControllerKt.isPermissionsHubEnabled()) updateLocation();
    }

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

    private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
+9 −0
Original line number Diff line number Diff line
@@ -249,6 +249,15 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout {
        requestLayout();
    }

    /**
     * Sets the list of ignored icon slots clearing the current list.
     * @param slots names of the icons to ignore
     */
    public void setIgnoredSlots(List<String> slots) {
        mIgnoredSlots.clear();
        addIgnoredSlots(slots);
    }

    /**
     * Layout is happening from end -> start
     */
Loading