blob: fd557a313ecb99ccbb2d79969774c5af673a0278 [file] [log] [blame]
/*
* Copyright (C) 2017 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.settings.location;
import android.app.ActivityManager;
import android.Manifest.permission;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import com.android.settings.Utils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import static com.android.settingslib.Utils.updateLocationMode;
import static com.android.settingslib.Utils.updateLocationEnabled;
import static com.android.settingslib.RestrictedLockUtils.checkIfRestrictionEnforced;
/**
* A class that listens to location settings change and modifies location settings
* settings.
*/
public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
private static final String TAG = "LocationEnabler";
@VisibleForTesting
static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
private final Context mContext;
private final UserManager mUserManager;
private final LocationModeChangeListener mListener;
@VisibleForTesting
BroadcastReceiver mReceiver;
public interface LocationModeChangeListener {
/** Called when location mode has changed. */
void onLocationModeChanged(int mode, boolean restricted);
}
public LocationEnabler(Context context, LocationModeChangeListener listener,
Lifecycle lifecycle) {
mContext = context;
mListener = listener;
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public void onResume() {
if (mReceiver == null) {
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received location mode change intent: " + intent);
}
refreshLocationMode();
}
};
}
mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
refreshLocationMode();
}
@Override
public void onPause() {
try {
mContext.unregisterReceiver(mReceiver);
} catch (RuntimeException e) {
// Ignore exceptions caused by race condition
}
}
void refreshLocationMode() {
final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
if (Log.isLoggable(TAG, Log.INFO)) {
Log.i(TAG, "Location mode has been changed");
}
if (mListener != null) {
mListener.onLocationModeChanged(mode, isRestricted());
}
}
void setLocationEnabled(boolean enabled) {
final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
if (isRestricted()) {
// Location toggling disabled by user restriction. Read the current location mode to
// update the location master switch.
if (Log.isLoggable(TAG, Log.INFO)) {
Log.i(TAG, "Restricted user, not setting location mode");
}
if (mListener != null) {
mListener.onLocationModeChanged(currentMode, true);
}
return;
}
updateLocationEnabled(mContext, enabled, UserHandle.myUserId(),
Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS);
refreshLocationMode();
}
void setLocationMode(int mode) {
final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
if (isRestricted()) {
// Location toggling disabled by user restriction. Read the current location mode to
// update the location master switch.
if (Log.isLoggable(TAG, Log.INFO)) {
Log.i(TAG, "Restricted user, not setting location mode");
}
if (mListener != null) {
mListener.onLocationModeChanged(currentMode, true);
}
return;
}
updateLocationMode(mContext, currentMode, mode, ActivityManager.getCurrentUser(),
Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS);
refreshLocationMode();
}
boolean isEnabled(int mode) {
return mode != Settings.Secure.LOCATION_MODE_OFF && !isRestricted();
}
/**
* Checking if device policy has put a location access lock-down on the managed profile.
*
* @return true if device policy has put a location access lock-down on the managed profile
*/
boolean isManagedProfileRestrictedByBase() {
final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
return managedProfile != null
&& hasShareLocationRestriction(managedProfile.getIdentifier());
}
RestrictedLockUtils.EnforcedAdmin getShareLocationEnforcedAdmin(int userId) {
RestrictedLockUtils.EnforcedAdmin admin = checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
if (admin == null) {
admin = RestrictedLockUtils.checkIfRestrictionEnforced(
mContext, UserManager.DISALLOW_CONFIG_LOCATION, userId);
}
return admin;
}
boolean hasShareLocationRestriction(int userId) {
return RestrictedLockUtils.hasBaseUserRestriction(
mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
}
private boolean isRestricted() {
return mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION);
}
}