19ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling/*
29ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * Copyright (C) 2017 The Android Open Source Project
39ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling *
49ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
59ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * except in compliance with the License. You may obtain a copy of the License at
69ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling *
79ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling *      http://www.apache.org/licenses/LICENSE-2.0
89ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling *
99ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * Unless required by applicable law or agreed to in writing, software distributed under the
109ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
119ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * KIND, either express or implied. See the License for the specific language governing
129ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * permissions and limitations under the License.
139ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling */
149ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingpackage com.android.settings.location;
159ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
161949600132d05da7e3785412b7fd8fc336c8205bMaggieimport android.app.ActivityManager;
179ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.Manifest.permission;
189ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.content.BroadcastReceiver;
199ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.content.Context;
209ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.content.Intent;
219ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.content.IntentFilter;
229ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.location.LocationManager;
239ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.os.UserHandle;
249ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.os.UserManager;
259ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.provider.Settings;
269ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.support.annotation.VisibleForTesting;
279ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport android.util.Log;
289ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
299ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport com.android.settings.Utils;
309ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport com.android.settingslib.RestrictedLockUtils;
319ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport com.android.settingslib.core.lifecycle.Lifecycle;
329ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport com.android.settingslib.core.lifecycle.LifecycleObserver;
339ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport com.android.settingslib.core.lifecycle.events.OnPause;
349ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingimport com.android.settingslib.core.lifecycle.events.OnResume;
359ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
361949600132d05da7e3785412b7fd8fc336c8205bMaggieimport static com.android.settingslib.Utils.updateLocationMode;
3785e2f61b2d349125e4bd5d7677cfa09ba09983caMaggieimport static com.android.settingslib.Utils.updateLocationEnabled;
38754ca518422a2a633fc4d49436db7b15b4be0e84yuemingwimport static com.android.settingslib.RestrictedLockUtils.checkIfRestrictionEnforced;
391949600132d05da7e3785412b7fd8fc336c8205bMaggie
4085e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie
419ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling/**
429ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * A class that listens to location settings change and modifies location settings
439ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * settings.
449ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling */
459ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingpublic class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
469ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
479ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private static final String TAG = "LocationEnabler";
489ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @VisibleForTesting
499ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
509ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
519ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
529ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private final Context mContext;
539ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private final UserManager mUserManager;
549ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private final LocationModeChangeListener mListener;
559ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
569ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @VisibleForTesting
579ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    BroadcastReceiver mReceiver;
589ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
599ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public interface LocationModeChangeListener {
609ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        /** Called when location mode has changed. */
619ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        void onLocationModeChanged(int mode, boolean restricted);
629ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
639ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
649ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public LocationEnabler(Context context, LocationModeChangeListener listener,
659ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            Lifecycle lifecycle) {
669ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mContext = context;
679ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mListener = listener;
689ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
699ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (lifecycle != null) {
709ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            lifecycle.addObserver(this);
719ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
729ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
739ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
749ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @Override
759ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public void onResume() {
769ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (mReceiver == null) {
779ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            mReceiver = new BroadcastReceiver() {
789ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                @Override
799ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                public void onReceive(Context context, Intent intent) {
809ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                    if (Log.isLoggable(TAG, Log.DEBUG)) {
819ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                        Log.d(TAG, "Received location mode change intent: " + intent);
829ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                    }
839ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                    refreshLocationMode();
849ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                }
859ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            };
869ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
879ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
889ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        refreshLocationMode();
899ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
909ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
919ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @Override
929ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public void onPause() {
939ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        try {
949ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            mContext.unregisterReceiver(mReceiver);
959ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        } catch (RuntimeException e) {
969ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            // Ignore exceptions caused by race condition
979ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
989ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
999ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1009ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    void refreshLocationMode() {
1019ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
1029ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
1039ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (Log.isLoggable(TAG, Log.INFO)) {
1049ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            Log.i(TAG, "Location mode has been changed");
1059ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
1069ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (mListener != null) {
1079ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            mListener.onLocationModeChanged(mode, isRestricted());
1089ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
1099ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1109ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
11185e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie    void setLocationEnabled(boolean enabled) {
11285e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie        final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
11385e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
11485e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie
11585e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie        if (isRestricted()) {
11685e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            // Location toggling disabled by user restriction. Read the current location mode to
11785e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            // update the location master switch.
11885e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            if (Log.isLoggable(TAG, Log.INFO)) {
11985e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                Log.i(TAG, "Restricted user, not setting location mode");
12085e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            }
12185e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            if (mListener != null) {
12285e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie                mListener.onLocationModeChanged(currentMode, true);
12385e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            }
12485e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie            return;
12585e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie        }
126e6032be8516fc0edfc5824093706349c6945e090Lifu Tang        updateLocationEnabled(mContext, enabled, UserHandle.myUserId(),
127e6032be8516fc0edfc5824093706349c6945e090Lifu Tang                Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS);
12885e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie        refreshLocationMode();
12985e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie    }
13085e2f61b2d349125e4bd5d7677cfa09ba09983caMaggie
1319ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    void setLocationMode(int mode) {
1329ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
1339ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
1349ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (isRestricted()) {
1359ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            // Location toggling disabled by user restriction. Read the current location mode to
1369ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            // update the location master switch.
1379ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            if (Log.isLoggable(TAG, Log.INFO)) {
1389ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                Log.i(TAG, "Restricted user, not setting location mode");
1399ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            }
1409ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            if (mListener != null) {
1419ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                mListener.onLocationModeChanged(currentMode, true);
1429ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            }
1439ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            return;
1449ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
1459ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
146e6032be8516fc0edfc5824093706349c6945e090Lifu Tang        updateLocationMode(mContext, currentMode, mode, ActivityManager.getCurrentUser(),
147e6032be8516fc0edfc5824093706349c6945e090Lifu Tang                Settings.Secure.LOCATION_CHANGER_SYSTEM_SETTINGS);
1489ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        refreshLocationMode();
1499ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1509ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1519ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    boolean isEnabled(int mode) {
1529ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return mode != Settings.Secure.LOCATION_MODE_OFF && !isRestricted();
1539ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1549ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1559ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    /**
1569ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     * Checking if device policy has put a location access lock-down on the managed profile.
1579ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     *
1589ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     * @return true if device policy has put a location access lock-down on the managed profile
1599ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     */
1609ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    boolean isManagedProfileRestrictedByBase() {
1619ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
1629ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return managedProfile != null
1639ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                && hasShareLocationRestriction(managedProfile.getIdentifier());
1649ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1659ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1669ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    RestrictedLockUtils.EnforcedAdmin getShareLocationEnforcedAdmin(int userId) {
167754ca518422a2a633fc4d49436db7b15b4be0e84yuemingw        RestrictedLockUtils.EnforcedAdmin admin =  checkIfRestrictionEnforced(
1689ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
169754ca518422a2a633fc4d49436db7b15b4be0e84yuemingw
170754ca518422a2a633fc4d49436db7b15b4be0e84yuemingw        if (admin == null) {
171754ca518422a2a633fc4d49436db7b15b4be0e84yuemingw            admin = RestrictedLockUtils.checkIfRestrictionEnforced(
172a1416d2849e866e6a9a53c13af82608ca876454fyuemingw                    mContext, UserManager.DISALLOW_CONFIG_LOCATION, userId);
173754ca518422a2a633fc4d49436db7b15b4be0e84yuemingw        }
174754ca518422a2a633fc4d49436db7b15b4be0e84yuemingw        return admin;
1759ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1769ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1779ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    boolean hasShareLocationRestriction(int userId) {
1789ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return RestrictedLockUtils.hasBaseUserRestriction(
1799ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
1809ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1819ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1829ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private boolean isRestricted() {
1839ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION);
1849ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1859ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling}
186