1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 package com.android.settings.location; 15 16 import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfRestrictionEnforced; 17 import static com.android.settingslib.Utils.updateLocationEnabled; 18 19 import android.content.BroadcastReceiver; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.IntentFilter; 23 import android.location.LocationManager; 24 import android.os.UserHandle; 25 import android.os.UserManager; 26 import android.provider.Settings; 27 import android.util.Log; 28 29 import androidx.annotation.VisibleForTesting; 30 31 import com.android.settings.Utils; 32 import com.android.settingslib.RestrictedLockUtils; 33 import com.android.settingslib.RestrictedLockUtilsInternal; 34 import com.android.settingslib.core.lifecycle.Lifecycle; 35 import com.android.settingslib.core.lifecycle.LifecycleObserver; 36 import com.android.settingslib.core.lifecycle.events.OnStart; 37 import com.android.settingslib.core.lifecycle.events.OnStop; 38 39 40 /** 41 * A class that listens to location settings change and modifies location settings 42 * settings. 43 */ 44 public class LocationEnabler implements LifecycleObserver, OnStart, OnStop { 45 46 private static final String TAG = "LocationEnabler"; 47 @VisibleForTesting 48 static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED = 49 new IntentFilter(LocationManager.MODE_CHANGED_ACTION); 50 51 private final Context mContext; 52 private final UserManager mUserManager; 53 private final LocationModeChangeListener mListener; 54 55 @VisibleForTesting 56 BroadcastReceiver mReceiver; 57 58 public interface LocationModeChangeListener { 59 /** Called when location mode has changed. */ onLocationModeChanged(int mode, boolean restricted)60 void onLocationModeChanged(int mode, boolean restricted); 61 } 62 LocationEnabler(Context context, LocationModeChangeListener listener, Lifecycle lifecycle)63 public LocationEnabler(Context context, LocationModeChangeListener listener, 64 Lifecycle lifecycle) { 65 mContext = context; 66 mListener = listener; 67 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 68 if (lifecycle != null) { 69 lifecycle.addObserver(this); 70 } 71 } 72 73 @Override onStart()74 public void onStart() { 75 if (mReceiver == null) { 76 mReceiver = new BroadcastReceiver() { 77 @Override 78 public void onReceive(Context context, Intent intent) { 79 if (Log.isLoggable(TAG, Log.DEBUG)) { 80 Log.d(TAG, "Received location mode change intent: " + intent); 81 } 82 refreshLocationMode(); 83 } 84 }; 85 } 86 mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED); 87 refreshLocationMode(); 88 } 89 90 @Override onStop()91 public void onStop() { 92 mContext.unregisterReceiver(mReceiver); 93 } 94 95 /** 96 * Get the current location enable state, and update listeners 97 */ refreshLocationMode()98 public void refreshLocationMode() { 99 final int mode = Settings.Secure.getInt(mContext.getContentResolver(), 100 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 101 if (Log.isLoggable(TAG, Log.INFO)) { 102 Log.i(TAG, "Location mode has been changed"); 103 } 104 if (mListener != null) { 105 mListener.onLocationModeChanged(mode, isRestricted()); 106 } 107 } 108 109 /** 110 * Set the device's location enable state 111 */ setLocationEnabled(boolean enabled)112 public void setLocationEnabled(boolean enabled) { 113 final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(), 114 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 115 116 if (isRestricted()) { 117 // Location toggling disabled by user restriction. Read the current location mode to 118 // update the location primary switch. 119 if (Log.isLoggable(TAG, Log.INFO)) { 120 Log.i(TAG, "Restricted user, not setting location mode"); 121 } 122 if (mListener != null) { 123 mListener.onLocationModeChanged(currentMode, true); 124 } 125 return; 126 } 127 updateLocationEnabled(mContext, enabled, UserHandle.myUserId(), 128 Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS); 129 refreshLocationMode(); 130 } 131 132 /** 133 * Checks if location is enabled, based on mode and restrictions. 134 */ isEnabled(int mode)135 public boolean isEnabled(int mode) { 136 return mode != Settings.Secure.LOCATION_MODE_OFF && !isRestricted(); 137 } 138 139 /** 140 * Checking if device policy has put a location access lock-down on the managed profile. 141 * 142 * @return true if device policy has put a location access lock-down on the managed profile 143 */ isManagedProfileRestrictedByBase()144 public boolean isManagedProfileRestrictedByBase() { 145 final UserHandle managedProfile = Utils.getManagedProfile(mUserManager); 146 return managedProfile != null 147 && hasShareLocationRestriction(managedProfile.getIdentifier()); 148 } 149 150 /** 151 * Gets the admin enforcement for location for the current user 152 */ getShareLocationEnforcedAdmin(int userId)153 public RestrictedLockUtils.EnforcedAdmin getShareLocationEnforcedAdmin(int userId) { 154 RestrictedLockUtils.EnforcedAdmin admin = checkIfRestrictionEnforced( 155 mContext, UserManager.DISALLOW_SHARE_LOCATION, userId); 156 157 if (admin == null) { 158 admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced( 159 mContext, UserManager.DISALLOW_CONFIG_LOCATION, userId); 160 } 161 return admin; 162 } 163 164 /** 165 * Check if the current user has a location restriction 166 */ hasShareLocationRestriction(int userId)167 public boolean hasShareLocationRestriction(int userId) { 168 return RestrictedLockUtilsInternal.hasBaseUserRestriction( 169 mContext, UserManager.DISALLOW_SHARE_LOCATION, userId); 170 } 171 isRestricted()172 private boolean isRestricted() { 173 return mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION); 174 } 175 } 176