LocationEnabler.java revision 1949600132d05da7e3785412b7fd8fc336c8205b
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;
371949600132d05da7e3785412b7fd8fc336c8205bMaggie
389ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling/**
399ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * A class that listens to location settings change and modifies location settings
409ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling * settings.
419ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling */
429ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Lingpublic class LocationEnabler implements LifecycleObserver, OnResume, OnPause {
439ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
449ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private static final String TAG = "LocationEnabler";
459ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @VisibleForTesting
469ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
479ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            new IntentFilter(LocationManager.MODE_CHANGED_ACTION);
489ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
499ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private final Context mContext;
509ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private final UserManager mUserManager;
519ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private final LocationModeChangeListener mListener;
529ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
539ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @VisibleForTesting
549ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    BroadcastReceiver mReceiver;
559ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
569ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public interface LocationModeChangeListener {
579ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        /** Called when location mode has changed. */
589ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        void onLocationModeChanged(int mode, boolean restricted);
599ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
609ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
619ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public LocationEnabler(Context context, LocationModeChangeListener listener,
629ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            Lifecycle lifecycle) {
639ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mContext = context;
649ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mListener = listener;
659ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
669ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (lifecycle != null) {
679ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            lifecycle.addObserver(this);
689ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
699ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
709ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
719ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @Override
729ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public void onResume() {
739ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (mReceiver == null) {
749ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            mReceiver = new BroadcastReceiver() {
759ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                @Override
769ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                public void onReceive(Context context, Intent intent) {
779ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                    if (Log.isLoggable(TAG, Log.DEBUG)) {
789ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                        Log.d(TAG, "Received location mode change intent: " + intent);
799ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                    }
809ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                    refreshLocationMode();
819ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                }
829ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            };
839ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
849ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
859ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        refreshLocationMode();
869ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
879ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
889ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    @Override
899ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    public void onPause() {
909ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        try {
919ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            mContext.unregisterReceiver(mReceiver);
929ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        } catch (RuntimeException e) {
939ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            // Ignore exceptions caused by race condition
949ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
959ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
969ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
979ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    void refreshLocationMode() {
989ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
999ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
1009ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (Log.isLoggable(TAG, Log.INFO)) {
1019ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            Log.i(TAG, "Location mode has been changed");
1029ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
1039ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (mListener != null) {
1049ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            mListener.onLocationModeChanged(mode, isRestricted());
1059ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
1069ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1079ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1089ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    void setLocationMode(int mode) {
1099ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
1109ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
1119ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        if (isRestricted()) {
1129ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            // Location toggling disabled by user restriction. Read the current location mode to
1139ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            // update the location master switch.
1149ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            if (Log.isLoggable(TAG, Log.INFO)) {
1159ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                Log.i(TAG, "Restricted user, not setting location mode");
1169ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            }
1179ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            if (mListener != null) {
1189ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                mListener.onLocationModeChanged(currentMode, true);
1199ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            }
1209ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling            return;
1219ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        }
1229ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1231949600132d05da7e3785412b7fd8fc336c8205bMaggie        updateLocationMode(mContext, currentMode, mode, ActivityManager.getCurrentUser());
1249ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        refreshLocationMode();
1259ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1269ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1279ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    boolean isEnabled(int mode) {
1289ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return mode != Settings.Secure.LOCATION_MODE_OFF && !isRestricted();
1299ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1309ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1319ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    /**
1329ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     * Checking if device policy has put a location access lock-down on the managed profile.
1339ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     *
1349ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     * @return true if device policy has put a location access lock-down on the managed profile
1359ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling     */
1369ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    boolean isManagedProfileRestrictedByBase() {
1379ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
1389ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return managedProfile != null
1399ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                && hasShareLocationRestriction(managedProfile.getIdentifier());
1409ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1419ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1429ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    RestrictedLockUtils.EnforcedAdmin getShareLocationEnforcedAdmin(int userId) {
1439ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return RestrictedLockUtils.checkIfRestrictionEnforced(
1449ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
1459ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1469ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1479ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    boolean hasShareLocationRestriction(int userId) {
1489ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return RestrictedLockUtils.hasBaseUserRestriction(
1499ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling                mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
1509ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1519ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling
1529ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    private boolean isRestricted() {
1539ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling        return mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION);
1549ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling    }
1559ed29a2e57bb6e0ad1626afdfb0517ba643ccc9fDoris Ling}
156