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 android.app.ActivityManager; 17 import android.Manifest.permission; 18 import android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.IntentFilter; 22 import android.location.LocationManager; 23 import android.os.UserHandle; 24 import android.os.UserManager; 25 import android.provider.Settings; 26 import android.support.annotation.VisibleForTesting; 27 import android.util.Log; 28 29 import com.android.settings.Utils; 30 import com.android.settingslib.RestrictedLockUtils; 31 import com.android.settingslib.core.lifecycle.Lifecycle; 32 import com.android.settingslib.core.lifecycle.LifecycleObserver; 33 import com.android.settingslib.core.lifecycle.events.OnPause; 34 import com.android.settingslib.core.lifecycle.events.OnResume; 35 36 import static com.android.settingslib.Utils.updateLocationMode; 37 import static com.android.settingslib.Utils.updateLocationEnabled; 38 import static com.android.settingslib.RestrictedLockUtils.checkIfRestrictionEnforced; 39 40 41 /** 42 * A class that listens to location settings change and modifies location settings 43 * settings. 44 */ 45 public class LocationEnabler implements LifecycleObserver, OnResume, OnPause { 46 47 private static final String TAG = "LocationEnabler"; 48 @VisibleForTesting 49 static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED = 50 new IntentFilter(LocationManager.MODE_CHANGED_ACTION); 51 52 private final Context mContext; 53 private final UserManager mUserManager; 54 private final LocationModeChangeListener mListener; 55 56 @VisibleForTesting 57 BroadcastReceiver mReceiver; 58 59 public interface LocationModeChangeListener { 60 /** Called when location mode has changed. */ 61 void onLocationModeChanged(int mode, boolean restricted); 62 } 63 64 public LocationEnabler(Context context, LocationModeChangeListener listener, 65 Lifecycle lifecycle) { 66 mContext = context; 67 mListener = listener; 68 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 69 if (lifecycle != null) { 70 lifecycle.addObserver(this); 71 } 72 } 73 74 @Override 75 public void onResume() { 76 if (mReceiver == null) { 77 mReceiver = new BroadcastReceiver() { 78 @Override 79 public void onReceive(Context context, Intent intent) { 80 if (Log.isLoggable(TAG, Log.DEBUG)) { 81 Log.d(TAG, "Received location mode change intent: " + intent); 82 } 83 refreshLocationMode(); 84 } 85 }; 86 } 87 mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED); 88 refreshLocationMode(); 89 } 90 91 @Override 92 public void onPause() { 93 try { 94 mContext.unregisterReceiver(mReceiver); 95 } catch (RuntimeException e) { 96 // Ignore exceptions caused by race condition 97 } 98 } 99 100 void refreshLocationMode() { 101 final int mode = Settings.Secure.getInt(mContext.getContentResolver(), 102 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 103 if (Log.isLoggable(TAG, Log.INFO)) { 104 Log.i(TAG, "Location mode has been changed"); 105 } 106 if (mListener != null) { 107 mListener.onLocationModeChanged(mode, isRestricted()); 108 } 109 } 110 111 void setLocationEnabled(boolean enabled) { 112 final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(), 113 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 114 115 if (isRestricted()) { 116 // Location toggling disabled by user restriction. Read the current location mode to 117 // update the location master switch. 118 if (Log.isLoggable(TAG, Log.INFO)) { 119 Log.i(TAG, "Restricted user, not setting location mode"); 120 } 121 if (mListener != null) { 122 mListener.onLocationModeChanged(currentMode, true); 123 } 124 return; 125 } 126 updateLocationEnabled(mContext, enabled, UserHandle.myUserId(), 127 Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS); 128 refreshLocationMode(); 129 } 130 131 void setLocationMode(int mode) { 132 final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(), 133 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF); 134 if (isRestricted()) { 135 // Location toggling disabled by user restriction. Read the current location mode to 136 // update the location master switch. 137 if (Log.isLoggable(TAG, Log.INFO)) { 138 Log.i(TAG, "Restricted user, not setting location mode"); 139 } 140 if (mListener != null) { 141 mListener.onLocationModeChanged(currentMode, true); 142 } 143 return; 144 } 145 146 updateLocationMode(mContext, currentMode, mode, ActivityManager.getCurrentUser(), 147 Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS); 148 refreshLocationMode(); 149 } 150 151 boolean isEnabled(int mode) { 152 return mode != Settings.Secure.LOCATION_MODE_OFF && !isRestricted(); 153 } 154 155 /** 156 * Checking if device policy has put a location access lock-down on the managed profile. 157 * 158 * @return true if device policy has put a location access lock-down on the managed profile 159 */ 160 boolean isManagedProfileRestrictedByBase() { 161 final UserHandle managedProfile = Utils.getManagedProfile(mUserManager); 162 return managedProfile != null 163 && hasShareLocationRestriction(managedProfile.getIdentifier()); 164 } 165 166 RestrictedLockUtils.EnforcedAdmin getShareLocationEnforcedAdmin(int userId) { 167 RestrictedLockUtils.EnforcedAdmin admin = checkIfRestrictionEnforced( 168 mContext, UserManager.DISALLOW_SHARE_LOCATION, userId); 169 170 if (admin == null) { 171 admin = RestrictedLockUtils.checkIfRestrictionEnforced( 172 mContext, UserManager.DISALLOW_CONFIG_LOCATION, userId); 173 } 174 return admin; 175 } 176 177 boolean hasShareLocationRestriction(int userId) { 178 return RestrictedLockUtils.hasBaseUserRestriction( 179 mContext, UserManager.DISALLOW_SHARE_LOCATION, userId); 180 } 181 182 private boolean isRestricted() { 183 return mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION); 184 } 185 } 186