Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9ed29a2e authored by Doris Ling's avatar Doris Ling
Browse files

Convert location settings to DashboardFragment.

- change LocationMode, LocationSettings, and ScanningSettings to be
DashboardFragment.
- remove LocationSettingsBase and moved base logics into base
controller.
- add controllers for the preferences under the 3 location settings
pages.

Fixes: 68719207
Test: make RunSettingsRoboTests
Change-Id: Icedf691c2a9f7989faebee39ea9da672209b7957
parent bbdc72c9
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -2,8 +2,6 @@ package com.android.settings.location;

import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;

import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -12,20 +10,11 @@ public class AppLocationPermissionPreferenceController extends
        AbstractPreferenceController implements PreferenceControllerMixin {

    private static final String KEY_APP_LEVEL_PERMISSIONS = "app_level_permissions";
    private Preference mPreference;

    public AppLocationPermissionPreferenceController(Context context) {
        super(context);
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        if (isAvailable()) {
            mPreference = screen.findPreference(KEY_APP_LEVEL_PERMISSIONS);
        }
    }

    @Override
    public String getPreferenceKey() {
        return KEY_APP_LEVEL_PERMISSIONS;
+60 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package com.android.settings.location;

import android.content.Context;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;

import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;

public class BluetoothScanningPreferenceController extends AbstractPreferenceController
        implements PreferenceControllerMixin {

    private static final String KEY_BLUETOOTH_SCAN_ALWAYS_AVAILABLE = "bluetooth_always_scanning";

    public BluetoothScanningPreferenceController(Context context) {
        super(context);
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

    @Override
    public String getPreferenceKey() {
        return KEY_BLUETOOTH_SCAN_ALWAYS_AVAILABLE;
    }

    @Override
    public void updateState(Preference preference) {
        ((SwitchPreference) preference).setChecked(
                Settings.Global.getInt(mContext.getContentResolver(),
                        Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1);
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        if (KEY_BLUETOOTH_SCAN_ALWAYS_AVAILABLE.equals(preference.getKey())) {
            Settings.Global.putInt(mContext.getContentResolver(),
                    Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
                    ((SwitchPreference) preference).isChecked() ? 1 : 0);
            return true;
        }
        return false;
    }
}
+44 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package com.android.settings.location;

import android.content.Context;
import android.os.UserManager;

import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;

/**
 * A base controller for preferences that listens to location settings change and modifies location
 * settings.
 */
public abstract class LocationBasePreferenceController extends AbstractPreferenceController
        implements PreferenceControllerMixin, LocationEnabler.LocationModeChangeListener {

    protected final UserManager mUserManager;
    protected final LocationEnabler mLocationEnabler;

    public LocationBasePreferenceController(Context context, Lifecycle lifecycle) {
        super(context);
        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
        mLocationEnabler = new LocationEnabler(context, this /* listener */, lifecycle);
    }

    @Override
    public boolean isAvailable() {
        return true;
    }

}
+166 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package com.android.settings.location;

import android.Manifest.permission;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.util.Log;

import com.android.settings.Utils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;

/**
 * A class that listens to location settings change and modifies location settings
 * settings.
 */
public class LocationEnabler implements LifecycleObserver, OnResume, OnPause {

    private static final String TAG = "LocationEnabler";
    @VisibleForTesting
    static final String MODE_CHANGING_ACTION =
            "com.android.settings.location.MODE_CHANGING";
    private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
    private static final String NEW_MODE_KEY = "NEW_MODE";
    @VisibleForTesting
    static final IntentFilter INTENT_FILTER_LOCATION_MODE_CHANGED =
            new IntentFilter(LocationManager.MODE_CHANGED_ACTION);

    private final Context mContext;
    private final UserManager mUserManager;
    private final LocationModeChangeListener mListener;

    @VisibleForTesting
    BroadcastReceiver mReceiver;

    public interface LocationModeChangeListener {
        /** Called when location mode has changed. */
        void onLocationModeChanged(int mode, boolean restricted);
    }

    public LocationEnabler(Context context, LocationModeChangeListener listener,
            Lifecycle lifecycle) {
        mContext = context;
        mListener = listener;
        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
        if (lifecycle != null) {
            lifecycle.addObserver(this);
        }
    }

    @Override
    public void onResume() {
        if (mReceiver == null) {
            mReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    if (Log.isLoggable(TAG, Log.DEBUG)) {
                        Log.d(TAG, "Received location mode change intent: " + intent);
                    }
                    refreshLocationMode();
                }
            };
        }
        mContext.registerReceiver(mReceiver, INTENT_FILTER_LOCATION_MODE_CHANGED);
        refreshLocationMode();
    }

    @Override
    public void onPause() {
        try {
            mContext.unregisterReceiver(mReceiver);
        } catch (RuntimeException e) {
            // Ignore exceptions caused by race condition
        }
    }

    void refreshLocationMode() {
        final int mode = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
        if (Log.isLoggable(TAG, Log.INFO)) {
            Log.i(TAG, "Location mode has been changed");
        }
        if (mListener != null) {
            mListener.onLocationModeChanged(mode, isRestricted());
        }
    }

    void setLocationMode(int mode) {
        final int currentMode = Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
        if (isRestricted()) {
            // Location toggling disabled by user restriction. Read the current location mode to
            // update the location master switch.
            if (Log.isLoggable(TAG, Log.INFO)) {
                Log.i(TAG, "Restricted user, not setting location mode");
            }
            if (mListener != null) {
                mListener.onLocationModeChanged(currentMode, true);
            }
            return;
        }

        updateLocationMode(currentMode, mode);
        refreshLocationMode();
    }

    boolean isEnabled(int mode) {
        return mode != Settings.Secure.LOCATION_MODE_OFF && !isRestricted();
    }

    /**
     * Checking if device policy has put a location access lock-down on the managed profile.
     *
     * @return true if device policy has put a location access lock-down on the managed profile
     */
    boolean isManagedProfileRestrictedByBase() {
        final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
        return managedProfile != null
                && hasShareLocationRestriction(managedProfile.getIdentifier());
    }

    RestrictedLockUtils.EnforcedAdmin getShareLocationEnforcedAdmin(int userId) {
        return RestrictedLockUtils.checkIfRestrictionEnforced(
                mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
    }

    boolean hasShareLocationRestriction(int userId) {
        return RestrictedLockUtils.hasBaseUserRestriction(
                mContext, UserManager.DISALLOW_SHARE_LOCATION, userId);
    }

    private boolean isRestricted() {
        return mUserManager.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION);
    }

    private boolean updateLocationMode(int oldMode, int newMode) {
        final Intent intent = new Intent(MODE_CHANGING_ACTION);
        intent.putExtra(CURRENT_MODE_KEY, oldMode);
        intent.putExtra(NEW_MODE_KEY, newMode);
        mContext.sendBroadcast(intent, permission.WRITE_SECURE_SETTINGS);
        return Settings.Secure.putInt(
                mContext.getContentResolver(), Settings.Secure.LOCATION_MODE, newMode);
    }
}
+103 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.settings.location;

import android.content.Context;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;

public class LocationForWorkPreferenceController extends LocationBasePreferenceController {

    /**
     * Key for managed profile location switch preference. Shown only
     * if there is a managed profile.
     */
    private static final String KEY_MANAGED_PROFILE_SWITCH = "managed_profile_location_switch";

    private RestrictedSwitchPreference mPreference;

    public LocationForWorkPreferenceController(Context context, Lifecycle lifecycle) {
        super(context, lifecycle);
    }

    @Override
    public boolean handlePreferenceTreeClick(Preference preference) {
        if (KEY_MANAGED_PROFILE_SWITCH.equals(preference.getKey())) {
            final boolean switchState = mPreference.isChecked();
            mUserManager.setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, !switchState,
                    Utils.getManagedProfile(mUserManager));
            mPreference.setSummary(switchState ?
                    R.string.switch_on_text : R.string.switch_off_text);
            return true;
        }
        return false;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mPreference =
                (RestrictedSwitchPreference) screen.findPreference(KEY_MANAGED_PROFILE_SWITCH);
    }

    @Override
    public boolean isAvailable() {
        // Looking for a managed profile. If there are no managed profiles then we are removing the
        // managed profile category.
        return Utils.getManagedProfile(mUserManager) != null;
    }

    @Override
    public String getPreferenceKey() {
        return KEY_MANAGED_PROFILE_SWITCH;
    }

    @Override
    public void onLocationModeChanged(int mode, boolean restricted) {
        if (!mPreference.isVisible() || !isAvailable()) {
            return;
        }
        final RestrictedLockUtils.EnforcedAdmin admin =
                mLocationEnabler.getShareLocationEnforcedAdmin(
                        Utils.getManagedProfile(mUserManager).getIdentifier());
        final boolean isRestrictedByBase = mLocationEnabler.isManagedProfileRestrictedByBase();
        if (!isRestrictedByBase && admin != null) {
            mPreference.setDisabledByAdmin(admin);
            mPreference.setChecked(false);
        } else {
            final boolean enabled = mLocationEnabler.isEnabled(mode);
            mPreference.setEnabled(enabled);

            int summaryResId = R.string.switch_off_text;
            if (!enabled) {
                mPreference.setChecked(false);
            } else {
                mPreference.setChecked(!isRestrictedByBase);
                summaryResId = (isRestrictedByBase ?
                        R.string.switch_off_text : R.string.switch_on_text);
            }
            mPreference.setSummary(summaryResId);
        }
    }
}
Loading