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 
refreshLocationMode()95     void refreshLocationMode() {
96         final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
97                 Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
98         if (Log.isLoggable(TAG, Log.INFO)) {
99             Log.i(TAG, "Location mode has been changed");
100         }
101         if (mListener != null) {
102             mListener.onLocationModeChanged(mode, isRestricted());
103         }
104     }
105 
setLocationEnabled(boolean enabled)106     void setLocationEnabled(boolean enabled) {
107         final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
108             Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
109 
110         if (isRestricted()) {
111             // Location toggling disabled by user restriction. Read the current location mode to
112             // update the location master switch.
113             if (Log.isLoggable(TAG, Log.INFO)) {
114                 Log.i(TAG, "Restricted user, not setting location mode");
115             }
116             if (mListener != null) {
117                 mListener.onLocationModeChanged(currentMode, true);
118             }
119             return;
120         }
121         updateLocationEnabled(mContext, enabled, UserHandle.myUserId(),
122                 Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS);
123         refreshLocationMode();
124     }
125 
isEnabled(int mode)126     boolean isEnabled(int mode) {
127         return mode != Settings.Secure.LOCATION_MODE_OFF && !isRestricted();
128     }
129 
130     /**
131      * Checking if device policy has put a location access lock-down on the managed profile.
132      *
133      * @return true if device policy has put a location access lock-down on the managed profile
134      */
isManagedProfileRestrictedByBase()135     boolean isManagedProfileRestrictedByBase() {
136         final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
137         return managedProfile != null
138                 && hasShareLocationRestriction(managedProfile.getIdentifier());
139     }
140 
getShareLocationEnforcedAdmin(int userId)141     RestrictedLockUtils.EnforcedAdmin getShareLocationEnforcedAdmin(int userId) {
142         RestrictedLockUtils.EnforcedAdmin admin =  checkIfRestrictionEnforced(
143                 mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
144 
145         if (admin == null) {
146             admin = RestrictedLockUtilsInternal.checkIfRestrictionEnforced(
147                     mContext, UserManager.DISALLOW_CONFIG_LOCATION, userId);
148         }
149         return admin;
150     }
151 
hasShareLocationRestriction(int userId)152     boolean hasShareLocationRestriction(int userId) {
153         return RestrictedLockUtilsInternal.hasBaseUserRestriction(
154                 mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
155     }
156 
isRestricted()157     private boolean isRestricted() {
158         return mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION);
159     }
160 }
161