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