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

Commit 37a81de5 authored by Nate Myren's avatar Nate Myren
Browse files

Observe location changes

Register a location change broadcast receiver, and allow liveDatas to
observe it. Also ensured that providers with background permissions do
not set their state to the background permission, without first checking
the provider state.

Fixes: 156793511
Test: Go to the PermissionApps Screen for location, or to the
permissions screen for Google Play Services, and enable or disable
location using the upper tray.

Change-Id: Iddbc025b095f723cbd6c9b5da78fbb851b3dfb59
parent 1e234767
Loading
Loading
Loading
Loading
+32 −6
Original line number Diff line number Diff line
@@ -51,13 +51,18 @@ class AppPermGroupUiInfoLiveData private constructor(
    private val packageName: String,
    private val permGroupName: String,
    private val user: UserHandle
) : SmartUpdateMediatorLiveData<AppPermGroupUiInfo>() {
) : SmartUpdateMediatorLiveData<AppPermGroupUiInfo>(), LocationUtils.LocationListener {

    private var isSpecialLocation = false
    private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
    private val permGroupLiveData = PermGroupLiveData[permGroupName]
    private val permissionStateLiveData = PermStateLiveData[packageName, permGroupName, user]

    init {
        isSpecialLocation = LocationUtils.isLocationGroupAndProvider(app,
            permGroupName, packageName) ||
            LocationUtils.isLocationGroupAndControllerExtraPackage(app, permGroupName, packageName)

        addSource(packageInfoLiveData) {
            updateIfActive()
        }
@@ -157,7 +162,7 @@ class AppPermGroupUiInfoLiveData private constructor(
        }

        if (groupInfo.packageName == Utils.OS_PKG &&
            !Utils.isModernPermissionGroup(groupInfo.name)) {
            !isModernPermissionGroup(groupInfo.name)) {
            return false
        }
        return true
@@ -212,6 +217,7 @@ class AppPermGroupUiInfoLiveData private constructor(
        allPermInfos: Map<String, LightPermInfo>,
        packageName: String
    ): PermGrantState {
        val specialLocationState = getIsSpecialLocationState()

        var hasPermWithBackground = false
        var isUserFixed = false
@@ -220,7 +226,8 @@ class AppPermGroupUiInfoLiveData private constructor(
            val permInfo = allPermInfos[permName] ?: continue
            permInfo.backgroundPermission?.let { backgroundPerm ->
                hasPermWithBackground = true
                if (permissionState[backgroundPerm]?.granted == true) {
                if (permissionState[backgroundPerm]?.granted == true &&
                    specialLocationState != false) {
                    return PermGrantState.PERMS_ALLOWED_ALWAYS
                }
            }
@@ -230,7 +237,7 @@ class AppPermGroupUiInfoLiveData private constructor(
                    permState.permFlags and PackageManager.FLAG_PERMISSION_ONE_TIME != 0
        }

        val anyAllowed = getIsSpecialLocationState() ?: permissionState.any { it.value.granted }
        val anyAllowed = specialLocationState ?: permissionState.any { it.value.granted }
        if (anyAllowed && (hasPermWithBackground || shouldShowAsForegroundGroup())) {
            if (isOneTime) {
                return PermGrantState.PERMS_ASK
@@ -259,8 +266,7 @@ class AppPermGroupUiInfoLiveData private constructor(

    private fun getIsSpecialLocationState(): Boolean? {
        val userContext = Utils.getUserContext(app, user)
        if (LocationUtils.isLocationGroupAndProvider(userContext, permGroupName,
                packageName)) {
        if (isSpecialLocation) {
            return LocationUtils.isLocationEnabled(userContext)
        }
        // The permission of the extra location controller package is determined by the
@@ -278,6 +284,26 @@ class AppPermGroupUiInfoLiveData private constructor(
                permGroupName.equals(Manifest.permission_group.MICROPHONE)
    }

    override fun onLocationStateChange(enabled: Boolean) {
        updateIfActive()
    }

    override fun onActive() {
        super.onActive()

        if (isSpecialLocation) {
            LocationUtils.addLocationListener(this)
        }
    }

    override fun onInactive() {
        super.onInactive()

        if (isSpecialLocation) {
            LocationUtils.removeLocationListener(this)
        }
    }

    /**
     * Repository for AppPermGroupUiInfoLiveDatas.
     * <p> Key value is a triple of string package name, string permission group name, and UserHandle,
+27 −3
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import com.android.permissioncontroller.permission.model.livedatatypes.LightAppP
import com.android.permissioncontroller.permission.model.livedatatypes.LightPackageInfo
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission
import com.android.permissioncontroller.permission.utils.LocationUtils
import com.android.permissioncontroller.permission.utils.SoftRestrictedPermissionPolicy
import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.permission.utils.Utils.OS_PKG

@@ -45,16 +44,21 @@ class LightAppPermGroupLiveData private constructor(
    private val packageName: String,
    private val permGroupName: String,
    private val user: UserHandle
) : SmartUpdateMediatorLiveData<LightAppPermGroup?>() {
) : SmartUpdateMediatorLiveData<LightAppPermGroup?>(), LocationUtils.LocationListener {

    val LOG_TAG = this::class.java.simpleName

    private var isSpecialLocation = false
    private val permStateLiveData = PermStateLiveData[packageName, permGroupName, user]
    private val permGroupLiveData = PermGroupLiveData[permGroupName]
    private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
    private val fgPermNamesLiveData = ForegroundPermNamesLiveData

    init {
        isSpecialLocation = LocationUtils.isLocationGroupAndProvider(app,
            permGroupName, packageName) ||
            LocationUtils.isLocationGroupAndControllerExtraPackage(app, permGroupName, packageName)

        addSource(fgPermNamesLiveData) {
            updateIfActive()
        }
@@ -113,7 +117,7 @@ class LightAppPermGroupLiveData private constructor(
        // Determine if this app permission group is a special location package or provider
        var specialLocationGrant: Boolean? = null
        val userContext = Utils.getUserContext(app, user)
        if (LocationUtils.isLocationGroupAndProvider(userContext, permGroupName, packageName)) {
        if (isSpecialLocation) {
            specialLocationGrant = LocationUtils.isLocationEnabled(app)
        }
        // The permission of the extra location controller package is determined by the status of
@@ -172,6 +176,26 @@ class LightAppPermGroupLiveData private constructor(
        return false
    }

    override fun onLocationStateChange(enabled: Boolean) {
        updateIfActive()
    }

    override fun onActive() {
        super.onActive()

        if (isSpecialLocation) {
            LocationUtils.addLocationListener(this)
        }
    }

    override fun onInactive() {
        super.onInactive()

        if (isSpecialLocation) {
            LocationUtils.removeLocationListener(this)
        }
    }

    /**
     * Repository for AppPermGroupLiveDatas.
     * <p> Key value is a triple of string package name, string permission group name, and
+69 −0
Original line number Diff line number Diff line
@@ -15,13 +15,17 @@
 */
package com.android.permissioncontroller.permission.utils;

import static android.location.LocationManager.EXTRA_LOCATION_ENABLED;

import android.Manifest;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.UserHandle;
import android.provider.Settings;
@@ -29,8 +33,11 @@ import android.util.Log;

import androidx.annotation.NonNull;

import com.android.permissioncontroller.PermissionControllerApplication;
import com.android.permissioncontroller.R;

import java.util.ArrayList;

public class LocationUtils {

    public static final String LOCATION_PERMISSION = Manifest.permission_group.LOCATION;
@@ -94,4 +101,66 @@ public class LocationUtils {
        }

    }

    /**
     * A Listener which responds to enabling or disabling of location on the device
     */
    public interface LocationListener {

        /**
         * A callback run any time we receive a broadcast stating the location enable state has
         * changed.
         * @param enabled Whether or not location is enabled
         */
        void onLocationStateChange(boolean enabled);
    }

    private static final ArrayList<LocationListener> sLocationListeners = new ArrayList<>();

    private static BroadcastReceiver sLocationBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            boolean isEnabled = intent.getBooleanExtra(EXTRA_LOCATION_ENABLED, true);
            synchronized (sLocationListeners) {
                for (LocationListener l: sLocationListeners) {
                    l.onLocationStateChange(isEnabled);
                }
            }
        }
    };

    /**
     * Add a LocationListener, which will be notified if the location provider is enabled or
     * disabled
     * @param listener the listener to add
     */
    public static void addLocationListener(LocationListener listener) {
        synchronized (sLocationListeners) {
            boolean wasEmpty = sLocationListeners.isEmpty();
            sLocationListeners.add(listener);
            if (wasEmpty) {
                IntentFilter intentFilter = new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
                PermissionControllerApplication.get().getApplicationContext()
                        .registerReceiverForAllUsers(sLocationBroadcastReceiver, intentFilter,
                                null, null);
            }
        }
    }

    /**
     * Remove a LocationListener
     * @param listener The listener to remove
     *
     * @return True if it was successfully removed, false otherwise
     */
    public static boolean removeLocationListener(LocationListener listener) {
        synchronized (sLocationListeners) {
            boolean success = sLocationListeners.remove(listener);
            if (success && sLocationListeners.isEmpty()) {
                PermissionControllerApplication.get().getApplicationContext()
                        .unregisterReceiver(sLocationBroadcastReceiver);
            }
            return success;
        }
    }
}