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
This commit is contained in:
Doris Ling
2017-11-02 16:42:45 -07:00
parent bbdc72c95a
commit 9ed29a2e57
35 changed files with 2657 additions and 626 deletions

View File

@@ -2,8 +2,6 @@ package com.android.settings.location;
import android.content.Context; import android.content.Context;
import android.provider.Settings; 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.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
@@ -12,20 +10,11 @@ public class AppLocationPermissionPreferenceController extends
AbstractPreferenceController implements PreferenceControllerMixin { AbstractPreferenceController implements PreferenceControllerMixin {
private static final String KEY_APP_LEVEL_PERMISSIONS = "app_level_permissions"; private static final String KEY_APP_LEVEL_PERMISSIONS = "app_level_permissions";
private Preference mPreference;
public AppLocationPermissionPreferenceController(Context context) { public AppLocationPermissionPreferenceController(Context context) {
super(context); super(context);
} }
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (isAvailable()) {
mPreference = screen.findPreference(KEY_APP_LEVEL_PERMISSIONS);
}
}
@Override @Override
public String getPreferenceKey() { public String getPreferenceKey() {
return KEY_APP_LEVEL_PERMISSIONS; return KEY_APP_LEVEL_PERMISSIONS;

View File

@@ -0,0 +1,60 @@
/*
* 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;
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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;
}
}

View File

@@ -0,0 +1,166 @@
/*
* 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);
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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);
}
}
}

View File

@@ -16,12 +16,20 @@
package com.android.settings.location; package com.android.settings.location;
import android.provider.Settings; import android.content.Context;
import android.support.v7.preference.PreferenceScreen; import android.provider.SearchIndexableResource;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.widget.RadioButtonPreference; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/** /**
* A page with 3 radio buttons to choose the location mode. * A page with 3 radio buttons to choose the location mode.
@@ -34,14 +42,9 @@ import com.android.settings.widget.RadioButtonPreference;
* *
* Sensors only: use GPS location only. * Sensors only: use GPS location only.
*/ */
public class LocationMode extends LocationSettingsBase public class LocationMode extends DashboardFragment {
implements RadioButtonPreference.OnClickListener {
private static final String KEY_HIGH_ACCURACY = "high_accuracy"; private static final String TAG = "LocationMode";
private RadioButtonPreference mHighAccuracy;
private static final String KEY_BATTERY_SAVING = "battery_saving";
private RadioButtonPreference mBatterySaving;
private static final String KEY_SENSORS_ONLY = "sensors_only";
private RadioButtonPreference mSensorsOnly;
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
@@ -49,95 +52,52 @@ public class LocationMode extends LocationSettingsBase
} }
@Override @Override
public void onResume() { protected int getPreferenceScreenResId() {
super.onResume(); return R.xml.location_mode;
createPreferenceHierarchy();
} }
@Override @Override
public void onPause() { protected String getLogTag() {
super.onPause(); return TAG;
}
private PreferenceScreen createPreferenceHierarchy() {
PreferenceScreen root = getPreferenceScreen();
if (root != null) {
root.removeAll();
}
addPreferencesFromResource(R.xml.location_mode);
root = getPreferenceScreen();
mHighAccuracy = (RadioButtonPreference) root.findPreference(KEY_HIGH_ACCURACY);
mBatterySaving = (RadioButtonPreference) root.findPreference(KEY_BATTERY_SAVING);
mSensorsOnly = (RadioButtonPreference) root.findPreference(KEY_SENSORS_ONLY);
mHighAccuracy.setOnClickListener(this);
mBatterySaving.setOnClickListener(this);
mSensorsOnly.setOnClickListener(this);
refreshLocationMode();
return root;
}
private void updateRadioButtons(RadioButtonPreference activated) {
if (activated == null) {
mHighAccuracy.setChecked(false);
mBatterySaving.setChecked(false);
mSensorsOnly.setChecked(false);
} else if (activated == mHighAccuracy) {
mHighAccuracy.setChecked(true);
mBatterySaving.setChecked(false);
mSensorsOnly.setChecked(false);
} else if (activated == mBatterySaving) {
mHighAccuracy.setChecked(false);
mBatterySaving.setChecked(true);
mSensorsOnly.setChecked(false);
} else if (activated == mSensorsOnly) {
mHighAccuracy.setChecked(false);
mBatterySaving.setChecked(false);
mSensorsOnly.setChecked(true);
}
} }
@Override @Override
public void onRadioButtonClicked(RadioButtonPreference emiter) { protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
int mode = Settings.Secure.LOCATION_MODE_OFF; return buildPreferenceControllers(context, getLifecycle());
if (emiter == mHighAccuracy) {
mode = Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
} else if (emiter == mBatterySaving) {
mode = Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
} else if (emiter == mSensorsOnly) {
mode = Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
}
setLocationMode(mode);
}
@Override
public void onModeChanged(int mode, boolean restricted) {
switch (mode) {
case Settings.Secure.LOCATION_MODE_OFF:
updateRadioButtons(null);
break;
case Settings.Secure.LOCATION_MODE_SENSORS_ONLY:
updateRadioButtons(mSensorsOnly);
break;
case Settings.Secure.LOCATION_MODE_BATTERY_SAVING:
updateRadioButtons(mBatterySaving);
break;
case Settings.Secure.LOCATION_MODE_HIGH_ACCURACY:
updateRadioButtons(mHighAccuracy);
break;
default:
break;
}
boolean enabled = (mode != Settings.Secure.LOCATION_MODE_OFF) && !restricted;
mHighAccuracy.setEnabled(enabled);
mBatterySaving.setEnabled(enabled);
mSensorsOnly.setEnabled(enabled);
} }
@Override @Override
public int getHelpResource() { public int getHelpResource() {
return R.string.help_url_location_access; return R.string.help_url_location_access;
} }
private static List<AbstractPreferenceController> buildPreferenceControllers(
Context context, Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new LocationModeHighAccuracyPreferenceController(context, lifecycle));
controllers.add(
new LocationModeBatterySavingPreferenceController(context, lifecycle));
controllers.add(new LocationModeSensorsOnlyPreferenceController(context, lifecycle));
return controllers;
}
/**
* For Search.
*/
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.location_mode;
return Arrays.asList(sir);
}
@Override
public List<AbstractPreferenceController> getPreferenceControllers(Context
context) {
return buildPreferenceControllers(context, null /* lifecycle */);
}
};
} }

View File

@@ -0,0 +1,40 @@
/*
* 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 com.android.settingslib.core.lifecycle.Lifecycle;
public class LocationModeBatterySavingPreferenceController
extends LocationModeRadioButtonPreferenceController {
private static final String KEY_BATTERY_SAVING = "battery_saving";
public LocationModeBatterySavingPreferenceController(Context context,
Lifecycle lifecycle) {
super(context, lifecycle);
}
@Override
public String getPreferenceKey() {
return KEY_BATTERY_SAVING;
}
@Override
protected int getLocationMode() {
return Settings.Secure.LOCATION_MODE_BATTERY_SAVING;
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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 com.android.settingslib.core.lifecycle.Lifecycle;
public class LocationModeHighAccuracyPreferenceController
extends LocationModeRadioButtonPreferenceController {
private static final String KEY_HIGH_ACCURACY = "high_accuracy";
public LocationModeHighAccuracyPreferenceController(Context context,
Lifecycle lifecycle) {
super(context, lifecycle);
}
@Override
public String getPreferenceKey() {
return KEY_HIGH_ACCURACY;
}
@Override
protected int getLocationMode() {
return Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
}
}

View File

@@ -0,0 +1,71 @@
/*
* 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.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settingslib.core.lifecycle.Lifecycle;
public class LocationModePreferenceController extends LocationBasePreferenceController {
/** Key for preference screen "Mode" */
private static final String KEY_LOCATION_MODE = "location_mode";
private final LocationSettings mParentFragment;
private Preference mPreference;
public LocationModePreferenceController(Context context, LocationSettings parent,
Lifecycle lifecycle) {
super(context, lifecycle);
mParentFragment = parent;
}
@Override
public String getPreferenceKey() {
return KEY_LOCATION_MODE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(KEY_LOCATION_MODE);
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (KEY_LOCATION_MODE.equals(preference.getKey())) {
final SettingsActivity activity = (SettingsActivity) mParentFragment.getActivity();
activity.startPreferencePanel(mParentFragment, LocationMode.class.getName(), null,
R.string.location_mode_screen_title, null, mParentFragment, 0);
return true;
}
return false;
}
@Override
public void onLocationModeChanged(int mode, boolean restricted) {
final int modeDescription = LocationPreferenceController.getLocationString(mode);
if (modeDescription != 0) {
mPreference.setSummary(modeDescription);
}
// Restricted user can't change the location mode, so disable the master switch. But in some
// corner cases, the location might still be enabled. In such case the master switch should
// be disabled but checked.
mPreference.setEnabled(mLocationEnabler.isEnabled(mode));
}
}

View File

@@ -0,0 +1,53 @@
/*
* 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.support.v7.preference.PreferenceScreen;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
public abstract class LocationModeRadioButtonPreferenceController
extends LocationBasePreferenceController
implements RadioButtonPreference.OnClickListener {
protected RadioButtonPreference mPreference;
public LocationModeRadioButtonPreferenceController(Context context, Lifecycle lifecycle) {
super(context, lifecycle);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = (RadioButtonPreference) screen.findPreference(getPreferenceKey());
mPreference.setOnClickListener(this);
}
@Override
public void onRadioButtonClicked(RadioButtonPreference emiter) {
mLocationEnabler.setLocationMode(getLocationMode());
}
@Override
public void onLocationModeChanged(int mode, boolean restricted) {
mPreference.setChecked(mode == getLocationMode());
mPreference.setEnabled(mLocationEnabler.isEnabled(mode));
}
/** Gets the location mode that this controller monitors. */
protected abstract int getLocationMode();
}

View File

@@ -0,0 +1,40 @@
/*
* 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 com.android.settingslib.core.lifecycle.Lifecycle;
public class LocationModeSensorsOnlyPreferenceController
extends LocationModeRadioButtonPreferenceController {
private static final String KEY_SENSORS_ONLY = "sensors_only";
public LocationModeSensorsOnlyPreferenceController(Context context,
Lifecycle lifecycle) {
super(context, lifecycle);
}
@Override
public String getPreferenceKey() {
return KEY_SENSORS_ONLY;
}
@Override
protected int getLocationMode() {
return Settings.Secure.LOCATION_MODE_SENSORS_ONLY;
}
}

View File

@@ -0,0 +1,130 @@
/*
* 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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.SettingInjectorService;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import android.util.Log;
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;
import java.util.List;
public class LocationServicePreferenceController extends LocationBasePreferenceController
implements LifecycleObserver, OnResume, OnPause {
private static final String TAG = "LocationServicePrefCtrl";
/** Key for preference category "Location services" */
private static final String KEY_LOCATION_SERVICES = "location_services";
@VisibleForTesting
static final IntentFilter INTENT_FILTER_INJECTED_SETTING_CHANGED =
new IntentFilter(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED);
private PreferenceCategory mCategoryLocationServices;
private final LocationSettings mFragment;
private final SettingsInjector mInjector;
/** Receives UPDATE_INTENT */
@VisibleForTesting
BroadcastReceiver mInjectedSettingsReceiver;
public LocationServicePreferenceController(Context context, LocationSettings fragment,
Lifecycle lifecycle) {
this(context, fragment, lifecycle, new SettingsInjector(context));
}
@VisibleForTesting
LocationServicePreferenceController(Context context, LocationSettings fragment,
Lifecycle lifecycle, SettingsInjector injector) {
super(context, lifecycle);
mFragment = fragment;
mInjector = injector;
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public String getPreferenceKey() {
return KEY_LOCATION_SERVICES;
}
@Override
public boolean isAvailable() {
// If managed profile has lock-down on location access then its injected location services
// must not be shown.
return mInjector.hasInjectedSettings(mLocationEnabler.isManagedProfileRestrictedByBase()
? UserHandle.myUserId() : UserHandle.USER_CURRENT);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mCategoryLocationServices =
(PreferenceCategory) screen.findPreference(KEY_LOCATION_SERVICES);
}
@Override
public void updateState(Preference preference) {
mCategoryLocationServices.removeAll();
LocationSettings.addPreferencesSorted(getLocationServices(), mCategoryLocationServices);
}
@Override
public void onLocationModeChanged(int mode, boolean restricted) {
// As a safety measure, also reloads on location mode change to ensure the settings are
// up-to-date even if an affected app doesn't send the setting changed broadcast.
mInjector.reloadStatusMessages();
}
@Override
public void onResume() {
if (mInjectedSettingsReceiver == null) {
mInjectedSettingsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received settings change intent: " + intent);
}
mInjector.reloadStatusMessages();
}
};
}
mContext.registerReceiver(
mInjectedSettingsReceiver, INTENT_FILTER_INJECTED_SETTING_CHANGED);
}
@Override
public void onPause() {
mContext.unregisterReceiver(mInjectedSettingsReceiver);
}
private List<Preference> getLocationServices() {
// If location access is locked down by device policy then we only show injected settings
// for the primary profile.
return mInjector.getInjectedSettings(mFragment.getPreferenceManager().getContext(),
mLocationEnabler.isManagedProfileRestrictedByBase()
? UserHandle.myUserId() : UserHandle.USER_CURRENT);
}
}

View File

@@ -16,37 +16,23 @@
package com.android.settings.location; package com.android.settings.location;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import android.app.Activity; import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.SettingInjectorService; import android.location.SettingInjectorService;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
import android.util.Log;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsActivity; import com.android.settings.SettingsActivity;
import com.android.settings.Utils; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.dashboard.SummaryLoader; import com.android.settings.dashboard.SummaryLoader;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settings.widget.AppPreference; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settings.widget.SwitchBar; import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.location.RecentLocationApps; import com.android.settingslib.location.RecentLocationApps;
import java.util.ArrayList; import java.util.ArrayList;
@@ -80,34 +66,11 @@ import java.util.List;
* other things, this simplifies integration with future changes to the default (AOSP) * other things, this simplifies integration with future changes to the default (AOSP)
* implementation. * implementation.
*/ */
public class LocationSettings extends LocationSettingsBase public class LocationSettings extends DashboardFragment {
implements SwitchBar.OnSwitchChangeListener, Indexable {
private static final String TAG = "LocationSettings"; private static final String TAG = "LocationSettings";
/** private LocationSwitchBarController mSwitchBarController;
* 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";
/** Key for preference screen "Mode" */
private static final String KEY_LOCATION_MODE = "location_mode";
/** Key for preference category "Recent location requests" */
private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
/** Key for preference category "Location services" */
private static final String KEY_LOCATION_SERVICES = "location_services";
private SwitchBar mSwitchBar;
private Switch mSwitch;
private boolean mValidListener = false;
private UserHandle mManagedProfile;
private RestrictedSwitchPreference mManagedProfileSwitch;
private Preference mLocationMode;
private PreferenceCategory mCategoryRecentLocationRequests;
/** Receives UPDATE_INTENT */
private BroadcastReceiver mReceiver;
private SettingsInjector injector;
private UserManager mUm;
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
@@ -117,52 +80,27 @@ public class LocationSettings extends LocationSettingsBase
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
final SettingsActivity activity = (SettingsActivity) getActivity(); final SettingsActivity activity = (SettingsActivity) getActivity();
mUm = (UserManager) activity.getSystemService(Context.USER_SERVICE); mSwitchBarController = new LocationSwitchBarController(
activity, activity.getSwitchBar(), getLifecycle());
setHasOptionsMenu(true);
mSwitchBar = activity.getSwitchBar();
mSwitch = mSwitchBar.getSwitch();
mSwitchBar.show();
setHasOptionsMenu(true);
} }
@Override @Override
public void onDestroyView() { protected int getPreferenceScreenResId() {
super.onDestroyView(); return R.xml.location_settings;
mSwitchBar.hide();
} }
@Override @Override
public void onResume() { protected String getLogTag() {
super.onResume(); return TAG;
createPreferenceHierarchy();
if (!mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
mValidListener = true;
}
} }
@Override @Override
public void onPause() { protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
try { return buildPreferenceControllers(context, this, getLifecycle());
getActivity().unregisterReceiver(mReceiver);
} catch (RuntimeException e) {
// Ignore exceptions caused by race condition
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Swallowing " + e);
}
}
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
mValidListener = false;
}
super.onPause();
} }
private void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) { static void addPreferencesSorted(List<Preference> prefs, PreferenceGroup container) {
// If there's some items to display, sort the items and add them to the container. // If there's some items to display, sort the items and add them to the container.
Collections.sort(prefs, new Comparator<Preference>() { Collections.sort(prefs, new Comparator<Preference>() {
@Override @Override
@@ -175,259 +113,22 @@ public class LocationSettings extends LocationSettingsBase
} }
} }
private PreferenceScreen createPreferenceHierarchy() {
final SettingsActivity activity = (SettingsActivity) getActivity();
PreferenceScreen root = getPreferenceScreen();
if (root != null) {
root.removeAll();
}
addPreferencesFromResource(R.xml.location_settings);
root = getPreferenceScreen();
setupManagedProfileCategory(root);
mLocationMode = root.findPreference(KEY_LOCATION_MODE);
mLocationMode.setOnPreferenceClickListener(
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
activity.startPreferencePanel(
LocationSettings.this,
LocationMode.class.getName(), null,
R.string.location_mode_screen_title, null, LocationSettings.this,
0);
return true;
}
});
RecentLocationApps recentApps = new RecentLocationApps(activity);
List<RecentLocationApps.Request> recentLocationRequests = recentApps.getAppList();
final AppLocationPermissionPreferenceController preferenceController =
new AppLocationPermissionPreferenceController(activity);
preferenceController.displayPreference(root);
mCategoryRecentLocationRequests =
(PreferenceCategory) root.findPreference(KEY_RECENT_LOCATION_REQUESTS);
List<Preference> recentLocationPrefs = new ArrayList<>(recentLocationRequests.size());
for (final RecentLocationApps.Request request : recentLocationRequests) {
final AppPreference pref = new AppPreference(getPrefContext());
pref.setSummary(request.contentDescription);
pref.setIcon(request.icon);
pref.setTitle(request.label);
pref.setOnPreferenceClickListener(
new PackageEntryClickedListener(request.packageName, request.userHandle));
recentLocationPrefs.add(pref);
}
if (recentLocationRequests.size() > 0) {
addPreferencesSorted(recentLocationPrefs, mCategoryRecentLocationRequests);
} else {
// If there's no item to display, add a "No recent apps" item.
Preference banner = new AppPreference(getPrefContext());
banner.setTitle(R.string.location_no_recent_apps);
banner.setSelectable(false);
mCategoryRecentLocationRequests.addPreference(banner);
}
boolean lockdownOnLocationAccess = false;
// Checking if device policy has put a location access lock-down on the managed
// profile. If managed profile has lock-down on location access then its
// injected location services must not be shown.
if (mManagedProfile != null
&& mUm.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile)) {
lockdownOnLocationAccess = true;
}
addLocationServices(activity, root, lockdownOnLocationAccess);
refreshLocationMode();
return root;
}
private void setupManagedProfileCategory(PreferenceScreen root) {
// Looking for a managed profile. If there are no managed profiles then we are removing the
// managed profile category.
mManagedProfile = Utils.getManagedProfile(mUm);
if (mManagedProfile == null) {
// There is no managed profile
root.removePreference(root.findPreference(KEY_MANAGED_PROFILE_SWITCH));
mManagedProfileSwitch = null;
} else {
mManagedProfileSwitch = (RestrictedSwitchPreference)root
.findPreference(KEY_MANAGED_PROFILE_SWITCH);
mManagedProfileSwitch.setOnPreferenceClickListener(null);
}
}
private void changeManagedProfileLocationAccessStatus(boolean mainSwitchOn) {
if (mManagedProfileSwitch == null) {
return;
}
mManagedProfileSwitch.setOnPreferenceClickListener(null);
final EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(getActivity(),
UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile.getIdentifier());
final boolean isRestrictedByBase = isManagedProfileRestrictedByBase();
if (!isRestrictedByBase && admin != null) {
mManagedProfileSwitch.setDisabledByAdmin(admin);
mManagedProfileSwitch.setChecked(false);
} else {
boolean enabled = mainSwitchOn;
mManagedProfileSwitch.setEnabled(enabled);
int summaryResId = R.string.switch_off_text;
if (!enabled) {
mManagedProfileSwitch.setChecked(false);
} else {
mManagedProfileSwitch.setChecked(!isRestrictedByBase);
summaryResId = (isRestrictedByBase ?
R.string.switch_off_text : R.string.switch_on_text);
mManagedProfileSwitch.setOnPreferenceClickListener(
mManagedProfileSwitchClickListener);
}
mManagedProfileSwitch.setSummary(summaryResId);
}
}
/**
* Add the settings injected by external apps into the "App Settings" category. Hides the
* category if there are no injected settings.
*
* Reloads the settings whenever receives
* {@link SettingInjectorService#ACTION_INJECTED_SETTING_CHANGED}.
*/
private void addLocationServices(Context context, PreferenceScreen root,
boolean lockdownOnLocationAccess) {
PreferenceCategory categoryLocationServices =
(PreferenceCategory) root.findPreference(KEY_LOCATION_SERVICES);
injector = new SettingsInjector(context);
// If location access is locked down by device policy then we only show injected settings
// for the primary profile.
final Context prefContext = categoryLocationServices.getContext();
final List<Preference> locationServices = injector.getInjectedSettings(prefContext,
lockdownOnLocationAccess ? UserHandle.myUserId() : UserHandle.USER_CURRENT);
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received settings change intent: " + intent);
}
injector.reloadStatusMessages();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED);
context.registerReceiver(mReceiver, filter);
if (locationServices.size() > 0) {
addPreferencesSorted(locationServices, categoryLocationServices);
} else {
// If there's no item to display, remove the whole category.
root.removePreference(categoryLocationServices);
}
}
@Override @Override
public int getHelpResource() { public int getHelpResource() {
return R.string.help_url_location_access; return R.string.help_url_location_access;
} }
@Override private static List<AbstractPreferenceController> buildPreferenceControllers(
public void onModeChanged(int mode, boolean restricted) { Context context, LocationSettings fragment, Lifecycle lifecycle) {
int modeDescription = LocationPreferenceController.getLocationString(mode); final List<AbstractPreferenceController> controllers = new ArrayList<>();
if (modeDescription != 0) { controllers.add(new LocationModePreferenceController(context, fragment, lifecycle));
mLocationMode.setSummary(modeDescription); controllers.add(new AppLocationPermissionPreferenceController(context));
} controllers.add(new LocationForWorkPreferenceController(context, lifecycle));
controllers.add(
// Restricted user can't change the location mode, so disable the master switch. But in some new RecentLocationRequestPreferenceController(context, fragment, lifecycle));
// corner cases, the location might still be enabled. In such case the master switch should controllers.add(
// be disabled but checked. new LocationServicePreferenceController(context, fragment, lifecycle));
final boolean enabled = (mode != android.provider.Settings.Secure.LOCATION_MODE_OFF); return controllers;
EnforcedAdmin admin = RestrictedLockUtils.checkIfRestrictionEnforced(getActivity(),
UserManager.DISALLOW_SHARE_LOCATION, UserHandle.myUserId());
boolean hasBaseUserRestriction = RestrictedLockUtils.hasBaseUserRestriction(getActivity(),
UserManager.DISALLOW_SHARE_LOCATION, UserHandle.myUserId());
// Disable the whole switch bar instead of the switch itself. If we disabled the switch
// only, it would be re-enabled again if the switch bar is not disabled.
if (!hasBaseUserRestriction && admin != null) {
mSwitchBar.setDisabledByAdmin(admin);
} else {
mSwitchBar.setEnabled(!restricted);
}
mLocationMode.setEnabled(enabled && !restricted);
mCategoryRecentLocationRequests.setEnabled(enabled);
if (enabled != mSwitch.isChecked()) {
// set listener to null so that that code below doesn't trigger onCheckedChanged()
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
}
mSwitch.setChecked(enabled);
if (mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
}
}
changeManagedProfileLocationAccessStatus(enabled);
// As a safety measure, also reloads on location mode change to ensure the settings are
// up-to-date even if an affected app doesn't send the setting changed broadcast.
injector.reloadStatusMessages();
}
/**
* Listens to the state change of the location master switch.
*/
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
if (isChecked) {
setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_PREVIOUS);
} else {
setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_OFF);
}
}
private boolean isManagedProfileRestrictedByBase() {
if (mManagedProfile == null) {
return false;
}
return mUm.hasBaseUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, mManagedProfile);
}
private Preference.OnPreferenceClickListener mManagedProfileSwitchClickListener =
new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
final boolean switchState = mManagedProfileSwitch.isChecked();
mUm.setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION,
!switchState, mManagedProfile);
mManagedProfileSwitch.setSummary(switchState ?
R.string.switch_on_text : R.string.switch_off_text);
return true;
}
};
private class PackageEntryClickedListener
implements Preference.OnPreferenceClickListener {
private String mPackage;
private UserHandle mUserHandle;
public PackageEntryClickedListener(String packageName, UserHandle userHandle) {
mPackage = packageName;
mUserHandle = userHandle;
}
@Override
public boolean onPreferenceClick(Preference preference) {
// start new fragment to display extended information
Bundle args = new Bundle();
args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mPackage);
((SettingsActivity) getActivity()).startPreferencePanelAsUser(
LocationSettings.this,
InstalledAppDetails.class.getName(), args,
R.string.application_info_label, null, mUserHandle);
return true;
}
} }
private static class SummaryProvider implements SummaryLoader.SummaryProvider { private static class SummaryProvider implements SummaryLoader.SummaryProvider {
@@ -470,5 +171,12 @@ public class LocationSettings extends LocationSettingsBase
sir.xmlResId = R.xml.location_settings; sir.xmlResId = R.xml.location_settings;
return Arrays.asList(sir); return Arrays.asList(sir);
} }
@Override
public List<AbstractPreferenceController> getPreferenceControllers(Context
context) {
return buildPreferenceControllers(context, null /* fragment */,
null /* lifecycle */);
}
}; };
} }

View File

@@ -1,133 +0,0 @@
/*
* Copyright (C) 2011 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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
import android.util.Log;
import com.android.settings.SettingsPreferenceFragment;
/**
* A base class that listens to location settings change and modifies location
* settings.
*/
public abstract class LocationSettingsBase extends SettingsPreferenceFragment {
private static final String TAG = "LocationSettingsBase";
/** Broadcast intent action when the location mode is about to change. */
private 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";
private int mCurrentMode;
private BroadcastReceiver mReceiver;
/**
* Whether the fragment is actively running.
*/
private boolean mActive = false;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
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();
}
};
}
@Override
public void onResume() {
super.onResume();
mActive = true;
IntentFilter filter = new IntentFilter();
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
getActivity().registerReceiver(mReceiver, filter);
}
@Override
public void onPause() {
try {
getActivity().unregisterReceiver(mReceiver);
} catch (RuntimeException e) {
// Ignore exceptions caused by race condition
}
super.onPause();
mActive = false;
}
/** Called when location mode has changed. */
public abstract void onModeChanged(int mode, boolean restricted);
public static boolean isRestricted(Context context) {
final UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
return um.hasUserRestriction(UserManager.DISALLOW_SHARE_LOCATION);
}
public static boolean updateLocationMode(Context context, int oldMode, int newMode) {
Intent intent = new Intent(MODE_CHANGING_ACTION);
intent.putExtra(CURRENT_MODE_KEY, oldMode);
intent.putExtra(NEW_MODE_KEY, newMode);
context.sendBroadcast(intent, android.Manifest.permission.WRITE_SECURE_SETTINGS);
return Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.LOCATION_MODE,
newMode);
}
public void setLocationMode(int mode) {
Context context = getActivity();
if (isRestricted(context)) {
// 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");
}
mode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF);
if (mActive) {
onModeChanged(mode, true);
}
return;
}
updateLocationMode(context, mCurrentMode, mode);
refreshLocationMode();
}
public void refreshLocationMode() {
if (mActive) {
int mode = Settings.Secure.getInt(getContentResolver(), Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF);
mCurrentMode = mode;
if (Log.isLoggable(TAG, Log.INFO)) {
Log.i(TAG, "Location mode has been changed");
}
onModeChanged(mode, isRestricted(getActivity()));
}
}
}

View File

@@ -0,0 +1,104 @@
/*
* 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.UserHandle;
import android.widget.Switch;
import com.android.settings.widget.SwitchBar;
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.OnStart;
import com.android.settingslib.core.lifecycle.events.OnStop;
public class LocationSwitchBarController implements SwitchBar.OnSwitchChangeListener,
LocationEnabler.LocationModeChangeListener, LifecycleObserver, OnStart, OnStop {
private final SwitchBar mSwitchBar;
private final Switch mSwitch;
private final LocationEnabler mLocationEnabler;
private boolean mValidListener;
public LocationSwitchBarController(Context context, SwitchBar switchBar,
Lifecycle lifecycle) {
mSwitchBar = switchBar;
mSwitch = mSwitchBar.getSwitch();
mLocationEnabler = new LocationEnabler(context, this /* listener */, lifecycle);
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public void onStart() {
if (!mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
mValidListener = true;
}
mSwitchBar.show();
}
@Override
public void onStop() {
mSwitchBar.hide();
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
mValidListener = false;
}
}
@Override
public void onLocationModeChanged(int mode, boolean restricted) {
// Restricted user can't change the location mode, so disable the master switch. But in some
// corner cases, the location might still be enabled. In such case the master switch should
// be disabled but checked.
final boolean enabled = mLocationEnabler.isEnabled(mode);
final int userId = UserHandle.myUserId();
final RestrictedLockUtils.EnforcedAdmin admin =
mLocationEnabler.getShareLocationEnforcedAdmin(userId);
final boolean hasBaseUserRestriction =
mLocationEnabler.hasShareLocationRestriction(userId);
// Disable the whole switch bar instead of the switch itself. If we disabled the switch
// only, it would be re-enabled again if the switch bar is not disabled.
if (!hasBaseUserRestriction && admin != null) {
mSwitchBar.setDisabledByAdmin(admin);
} else {
mSwitchBar.setEnabled(!restricted);
}
if (enabled != mSwitch.isChecked()) {
// set listener to null so that that code below doesn't trigger onCheckedChanged()
if (mValidListener) {
mSwitchBar.removeOnSwitchChangeListener(this);
}
mSwitch.setChecked(enabled);
if (mValidListener) {
mSwitchBar.addOnSwitchChangeListener(this);
}
}
}
/**
* Listens to the state change of the location master switch.
*/
@Override
public void onSwitchChanged(Switch switchView, boolean isChecked) {
mLocationEnabler.setLocationMode(isChecked
? android.provider.Settings.Secure.LOCATION_MODE_PREVIOUS
: android.provider.Settings.Secure.LOCATION_MODE_OFF);
}
}

View File

@@ -0,0 +1,137 @@
/*
* 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.Bundle;
import android.os.UserHandle;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.widget.AppPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.location.RecentLocationApps;
import java.util.ArrayList;
import java.util.List;
public class RecentLocationRequestPreferenceController extends LocationBasePreferenceController {
/** Key for preference category "Recent location requests" */
private static final String KEY_RECENT_LOCATION_REQUESTS = "recent_location_requests";
private final LocationSettings mFragment;
private final RecentLocationApps mRecentLocationApps;
private PreferenceCategory mCategoryRecentLocationRequests;
@VisibleForTesting
static class PackageEntryClickedListener implements Preference.OnPreferenceClickListener {
private final LocationSettings mFragment;
private final String mPackage;
private final UserHandle mUserHandle;
public PackageEntryClickedListener(LocationSettings fragment, String packageName,
UserHandle userHandle) {
mFragment = fragment;
mPackage = packageName;
mUserHandle = userHandle;
}
@Override
public boolean onPreferenceClick(Preference preference) {
// start new fragment to display extended information
final Bundle args = new Bundle();
args.putString(InstalledAppDetails.ARG_PACKAGE_NAME, mPackage);
((SettingsActivity) mFragment.getActivity()).startPreferencePanelAsUser(
mFragment,
InstalledAppDetails.class.getName(), args,
R.string.application_info_label, null, mUserHandle);
return true;
}
}
public RecentLocationRequestPreferenceController(Context context, LocationSettings fragment,
Lifecycle lifecycle) {
this(context, fragment, lifecycle, new RecentLocationApps(context));
}
@VisibleForTesting
RecentLocationRequestPreferenceController(Context context, LocationSettings fragment,
Lifecycle lifecycle, RecentLocationApps recentApps) {
super(context, lifecycle);
mFragment = fragment;
mRecentLocationApps = recentApps;
}
@Override
public String getPreferenceKey() {
return KEY_RECENT_LOCATION_REQUESTS;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mCategoryRecentLocationRequests =
(PreferenceCategory) screen.findPreference(KEY_RECENT_LOCATION_REQUESTS);
}
@Override
public void updateState(Preference preference) {
mCategoryRecentLocationRequests.removeAll();
final Context prefContext = preference.getContext();
final List<RecentLocationApps.Request> recentLocationRequests =
mRecentLocationApps.getAppList();
final List<Preference> recentLocationPrefs = new ArrayList<>(recentLocationRequests.size());
for (final RecentLocationApps.Request request : recentLocationRequests) {
recentLocationPrefs.add(createAppPreference(prefContext, request));
}
if (recentLocationRequests.size() > 0) {
LocationSettings.addPreferencesSorted(
recentLocationPrefs, mCategoryRecentLocationRequests);
} else {
// If there's no item to display, add a "No recent apps" item.
final Preference banner = createAppPreference(prefContext);
banner.setTitle(R.string.location_no_recent_apps);
banner.setSelectable(false);
mCategoryRecentLocationRequests.addPreference(banner);
}
}
@Override
public void onLocationModeChanged(int mode, boolean restricted) {
mCategoryRecentLocationRequests.setEnabled(mLocationEnabler.isEnabled(mode));
}
@VisibleForTesting
AppPreference createAppPreference(Context prefContext) {
return new AppPreference(prefContext);
}
@VisibleForTesting
AppPreference createAppPreference(Context prefContext, RecentLocationApps.Request request) {
final AppPreference pref = createAppPreference(prefContext);
pref.setSummary(request.contentDescription);
pref.setIcon(request.icon);
pref.setTitle(request.label);
pref.setOnPreferenceClickListener(new PackageEntryClickedListener(
mFragment, request.packageName, request.userHandle));
return pref;
}
}

View File

@@ -18,26 +18,23 @@ package com.android.settings.location;
import android.content.Context; import android.content.Context;
import android.provider.SearchIndexableResource; import android.provider.SearchIndexableResource;
import android.provider.Settings.Global;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
* A page that configures the background scanning settings for Wi-Fi and Bluetooth. * A page that configures the background scanning settings for Wi-Fi and Bluetooth.
*/ */
public class ScanningSettings extends SettingsPreferenceFragment implements Indexable { public class ScanningSettings extends DashboardFragment {
private static final String KEY_WIFI_SCAN_ALWAYS_AVAILABLE = "wifi_always_scanning"; private static final String TAG = "ScanningSettings";
private static final String KEY_BLUETOOTH_SCAN_ALWAYS_AVAILABLE = "bluetooth_always_scanning";
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
@@ -45,48 +42,25 @@ public class ScanningSettings extends SettingsPreferenceFragment implements Inde
} }
@Override @Override
public void onResume() { protected int getPreferenceScreenResId() {
super.onResume(); return R.xml.location_scanning;
createPreferenceHierarchy();
}
private PreferenceScreen createPreferenceHierarchy() {
PreferenceScreen root = getPreferenceScreen();
if (root != null) {
root.removeAll();
}
addPreferencesFromResource(R.xml.location_scanning);
root = getPreferenceScreen();
initPreferences();
return root;
}
private void initPreferences() {
final SwitchPreference wifiScanAlwaysAvailable =
(SwitchPreference) findPreference(KEY_WIFI_SCAN_ALWAYS_AVAILABLE);
wifiScanAlwaysAvailable.setChecked(Global.getInt(getContentResolver(),
Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1);
final SwitchPreference bleScanAlwaysAvailable =
(SwitchPreference) findPreference(KEY_BLUETOOTH_SCAN_ALWAYS_AVAILABLE);
bleScanAlwaysAvailable.setChecked(Global.getInt(getContentResolver(),
Global.BLE_SCAN_ALWAYS_AVAILABLE, 0) == 1);
} }
@Override @Override
public boolean onPreferenceTreeClick(Preference preference) { protected String getLogTag() {
String key = preference.getKey(); return TAG;
if (KEY_WIFI_SCAN_ALWAYS_AVAILABLE.equals(key)) {
Global.putInt(getContentResolver(),
Global.WIFI_SCAN_ALWAYS_AVAILABLE,
((SwitchPreference) preference).isChecked() ? 1 : 0);
} else if (KEY_BLUETOOTH_SCAN_ALWAYS_AVAILABLE.equals(key)) {
Global.putInt(getContentResolver(),
Global.BLE_SCAN_ALWAYS_AVAILABLE,
((SwitchPreference) preference).isChecked() ? 1 : 0);
} else {
return super.onPreferenceTreeClick(preference);
} }
return true;
@Override
protected List<AbstractPreferenceController> getPreferenceControllers(Context context) {
return buildPreferenceControllers(context);
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new WifiScanningPreferenceController(context));
controllers.add(new BluetoothScanningPreferenceController(context));
return controllers;
} }
/** /**
@@ -101,5 +75,11 @@ public class ScanningSettings extends SettingsPreferenceFragment implements Inde
sir.xmlResId = R.xml.location_scanning; sir.xmlResId = R.xml.location_scanning;
return Arrays.asList(sir); return Arrays.asList(sir);
} }
@Override
public List<AbstractPreferenceController> getPreferenceControllers(Context
context) {
return buildPreferenceControllers(context);
}
}; };
} }

View File

@@ -30,6 +30,7 @@ import android.graphics.drawable.Drawable;
import android.location.SettingInjectorService; import android.location.SettingInjectorService;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.Messenger; import android.os.Messenger;
import android.os.SystemClock; import android.os.SystemClock;
@@ -252,6 +253,28 @@ class SettingsInjector {
return prefs; return prefs;
} }
/**
* Checks wheteher there is any preference that other apps have injected.
*
* @param profileId Identifier of the user/profile to obtain the injected settings for or
* UserHandle.USER_CURRENT for all profiles associated with current user.
*/
public boolean hasInjectedSettings(final int profileId) {
final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
final List<UserHandle> profiles = um.getUserProfiles();
final int profileCount = profiles.size();
for (int i = 0; i < profileCount; ++i) {
final UserHandle userHandle = profiles.get(i);
if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
Iterable<InjectedSetting> settings = getSettings(userHandle);
for (InjectedSetting setting : settings) {
return true;
}
}
}
return false;
}
/** /**
* Reloads the status messages for all the preference items. * Reloads the status messages for all the preference items.
*/ */
@@ -338,6 +361,9 @@ class SettingsInjector {
private boolean mReloadRequested; private boolean mReloadRequested;
private StatusLoadingHandler() {
super(Looper.getMainLooper());
}
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
if (Log.isLoggable(TAG, Log.DEBUG)) { if (Log.isLoggable(TAG, Log.DEBUG)) {

View File

@@ -0,0 +1,60 @@
/*
* 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 WifiScanningPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin {
private static final String KEY_WIFI_SCAN_ALWAYS_AVAILABLE = "wifi_always_scanning";
public WifiScanningPreferenceController(Context context) {
super(context);
}
@Override
public boolean isAvailable() {
return true;
}
@Override
public String getPreferenceKey() {
return KEY_WIFI_SCAN_ALWAYS_AVAILABLE;
}
@Override
public void updateState(Preference preference) {
((SwitchPreference) preference).setChecked(
Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0) == 1);
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (KEY_WIFI_SCAN_ALWAYS_AVAILABLE.equals(preference.getKey())) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
((SwitchPreference) preference).isChecked() ? 1 : 0);
return true;
}
return false;
}
}

View File

@@ -60,6 +60,7 @@ import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment;
import com.android.settings.inputmethod.PhysicalKeyboardFragment; import com.android.settings.inputmethod.PhysicalKeyboardFragment;
import com.android.settings.inputmethod.VirtualKeyboardFragment; import com.android.settings.inputmethod.VirtualKeyboardFragment;
import com.android.settings.language.LanguageAndInputSettings; import com.android.settings.language.LanguageAndInputSettings;
import com.android.settings.location.LocationMode;
import com.android.settings.location.LocationSettings; import com.android.settings.location.LocationSettings;
import com.android.settings.location.ScanningSettings; import com.android.settings.location.ScanningSettings;
import com.android.settings.network.NetworkDashboardFragment; import com.android.settings.network.NetworkDashboardFragment;
@@ -129,6 +130,7 @@ public final class SearchIndexableResources {
addIndex(GestureSettings.class); addIndex(GestureSettings.class);
addIndex(LanguageAndInputSettings.class); addIndex(LanguageAndInputSettings.class);
addIndex(LocationSettings.class); addIndex(LocationSettings.class);
addIndex(LocationMode.class);
addIndex(ScanningSettings.class); addIndex(ScanningSettings.class);
addIndex(SecuritySettings.class); addIndex(SecuritySettings.class);
addIndex(ScreenLockSettings.class); addIndex(ScreenLockSettings.class);

View File

@@ -1,4 +1,3 @@
com.android.settings.location.LocationMode
com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment com.android.settings.accessibility.ToggleScreenMagnificationPreferenceFragment
com.android.settings.deviceinfo.SimStatus com.android.settings.deviceinfo.SimStatus
com.android.settings.deviceinfo.PrivateVolumeForget com.android.settings.deviceinfo.PrivateVolumeForget

View File

@@ -1,13 +1,9 @@
package com.android.settings.location; package com.android.settings.location;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.provider.Settings; import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -24,43 +20,33 @@ import org.robolectric.annotation.Config;
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class AppLocationPermissionPreferenceControllerTest { public class AppLocationPermissionPreferenceControllerTest {
@Mock(answer = RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen;
private AppLocationPermissionPreferenceController mController; private AppLocationPermissionPreferenceController mController;
@Mock @Mock
private Context mContext; private Context mContext;
private Preference mPreference;
@Before @Before
public void setUp() { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;
mController = new AppLocationPermissionPreferenceController(mContext); mController = new AppLocationPermissionPreferenceController(mContext);
mPreference = new Preference(mContext);
mPreference.setKey(mController.getPreferenceKey());
when(mScreen.findPreference(mPreference.getKey())).thenReturn(mPreference);
} }
@Test @Test
public void displayPreference_shouldRemovePreference() { public void isAvailable_noLocationLinkPermission_shouldReturnFalse() {
Settings.System.putInt(mContext.getContentResolver(), Settings.System.putInt(mContext.getContentResolver(),
android.provider.Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED, android.provider.Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
0); 0);
mController.displayPreference(mScreen); assertThat(mController.isAvailable()).isFalse();
assertThat(mPreference.isVisible()).isFalse();
} }
@Test @Test
public void displayPreference_shouldNotRemovePreference() { public void displayPreference_hasLocationLinkPermission_shouldReturnTrue() {
Settings.System.putInt(mContext.getContentResolver(), Settings.System.putInt(mContext.getContentResolver(),
android.provider.Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED, android.provider.Settings.Global.LOCATION_SETTINGS_LINK_TO_PERMISSIONS_ENABLED,
1); 1);
mController.displayPreference(mScreen);
assertThat(mPreference.isVisible()).isTrue(); assertThat(mController.isAvailable()).isTrue();
} }
} }

View File

@@ -0,0 +1,97 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class BluetoothScanningPreferenceControllerTest {
@Mock
private SwitchPreference mPreference;
private Context mContext;
private BluetoothScanningPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new BluetoothScanningPreferenceController(mContext);
when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
}
@Test
public void updateState_bluetoothScanningEnabled_shouldCheckedPreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
public void updateState_bluetoothScanningDisabled_shouldUncheckedPreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void handlePreferenceTreeClick_checked_shouldEnableBluetoothScanning() {
when(mPreference.isChecked()).thenReturn(true);
mController.handlePreferenceTreeClick(mPreference);
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0)).isEqualTo(1);
}
@Test
public void handlePreferenceTreeClick_unchecked_shouldDisableBluetoothScanning() {
when(mPreference.isChecked()).thenReturn(false);
mController.handlePreferenceTreeClick(mPreference);
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 1)).isEqualTo(0);
}
}

View File

@@ -0,0 +1,218 @@
/*
* 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 static android.Manifest.permission.WRITE_SECURE_SETTINGS;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationEnablerTest {
@Mock
private UserManager mUserManager;
@Mock
private LocationEnabler.LocationModeChangeListener mListener;
private Context mContext;
private LocationEnabler mEnabler;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
mEnabler = spy(new LocationEnabler(mContext, mListener, new Lifecycle()));
}
@Test
public void onResume_shouldSetActiveAndRegisterListener() {
mEnabler.onResume();
verify(mContext).registerReceiver(eq(mEnabler.mReceiver),
eq(mEnabler.INTENT_FILTER_LOCATION_MODE_CHANGED));
}
@Test
public void onResume_shouldRefreshLocationMode() {
mEnabler.onResume();
verify(mEnabler).refreshLocationMode();
}
@Test
public void onPause_shouldUnregisterListener() {
mEnabler.onPause();
verify(mContext).unregisterReceiver(mEnabler.mReceiver);
}
@Test
public void onReceive_shouldRefreshLocationMode() {
mEnabler.onResume();
reset(mListener);
mEnabler.mReceiver.onReceive(mContext, new Intent());
verify(mListener).onLocationModeChanged(anyInt(), anyBoolean());
}
@Test
public void isEnabled_locationOff_shouldReturnFalse() {
assertThat(mEnabler.isEnabled(Settings.Secure.LOCATION_MODE_OFF)).isFalse();
}
@Test
public void isEnabled_restricted_shouldReturnFalse() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(true);
assertThat(mEnabler.isEnabled(Settings.Secure.LOCATION_MODE_OFF)).isFalse();
}
@Test
public void isEnabled_locationONotRestricted_shouldReturnTrue() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
assertThat(mEnabler.isEnabled(Settings.Secure.LOCATION_MODE_BATTERY_SAVING)).isTrue();
}
@Test
public void refreshLocationMode_shouldCallOnLocationModeChanged() {
mEnabler.refreshLocationMode();
verify(mListener).onLocationModeChanged(anyInt(), anyBoolean());
}
@Test
public void setLocationMode_restricted_shouldSetCurrentMode() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(true);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
verify(mListener)
.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, true);
}
@Test
public void setLocationMode_notRestricted_shouldUpdateSecureSettings() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING))
.isEqualTo(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
}
@Test
public void setLocationMode_notRestricted_shouldRefreshLocation() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
verify(mEnabler).refreshLocationMode();
}
@Test
public void setLocationMode_notRestricted_shouldBroadcastUpdate() {
when(mUserManager.hasUserRestriction(anyString())).thenReturn(false);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
mEnabler.setLocationMode(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
verify(mContext).sendBroadcast(argThat(actionMatches(mEnabler.MODE_CHANGING_ACTION)),
eq(WRITE_SECURE_SETTINGS));
}
@Test
public void isManagedProfileRestrictedByBase_notManagedProfile_shouldReturnFalse() {
assertThat(mEnabler.isManagedProfileRestrictedByBase()).isFalse();
}
@Test
public void isManagedProfileRestrictedByBase_notRestricted_shouldReturnFalse() {
mockManagedProfile();
doReturn(false).when(mEnabler).hasShareLocationRestriction(anyInt());
assertThat(mEnabler.isManagedProfileRestrictedByBase()).isFalse();
}
@Test
public void isManagedProfileRestrictedByBase_hasManagedProfile_shouldReturnFalse() {
mockManagedProfile();
doReturn(true).when(mEnabler).hasShareLocationRestriction(anyInt());
assertThat(mEnabler.isManagedProfileRestrictedByBase()).isTrue();
}
private void mockManagedProfile() {
final List<UserHandle> userProfiles = new ArrayList<>();
final UserHandle userHandle = mock(UserHandle.class);
when(userHandle.getIdentifier()).thenReturn(5);
userProfiles.add(userHandle);
when(mUserManager.getUserProfiles()).thenReturn(userProfiles);
when(mUserManager.getUserHandle()).thenReturn(1);
when(mUserManager.getUserInfo(5))
.thenReturn(new UserInfo(5, "user 5", UserInfo.FLAG_MANAGED_PROFILE));
}
private static ArgumentMatcher<Intent> actionMatches(String expected) {
return intent -> TextUtils.equals(expected, intent.getAction());
}
}

View File

@@ -0,0 +1,193 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import com.android.settingslib.RestrictedSwitchPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationForWorkPreferenceControllerTest {
@Mock
private RestrictedSwitchPreference mPreference;
@Mock
private PreferenceScreen mScreen;
@Mock
private UserManager mUserManager;
@Mock
private LocationEnabler mEnabler;
@Mock
private UserHandle mUserHandle;
private Context mContext;
private LocationForWorkPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
mController = spy(new LocationForWorkPreferenceController(mContext, new Lifecycle()));
mockManagedProfile();
ReflectionHelpers.setField(mController, "mLocationEnabler", mEnabler);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
final String key = mController.getPreferenceKey();
when(mPreference.getKey()).thenReturn(key);
when(mPreference.isVisible()).thenReturn(true);
}
@Test
public void handlePreferenceTreeClick_preferenceChecked_shouldSetRestrictionAndOnSummary() {
mController.displayPreference(mScreen);
when(mPreference.isChecked()).thenReturn(true);
mController.handlePreferenceTreeClick(mPreference);
verify(mUserManager).setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, false,
mUserHandle);
verify(mPreference).setSummary(R.string.switch_on_text);
}
@Test
public void handlePreferenceTreeClick_preferenceUnchecked_shouldSetRestritionAndOffSummary() {
mController.displayPreference(mScreen);
when(mPreference.isChecked()).thenReturn(false);
mController.handlePreferenceTreeClick(mPreference);
verify(mUserManager).setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true,
mUserHandle);
verify(mPreference).setSummary(R.string.switch_off_text);
}
@Test
public void isAvailable_noManagedProfile_shouldReturnFalse() {
when(mUserManager.getUserProfiles()).thenReturn(new ArrayList<UserHandle>());
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_hasManagedProfile_shouldReturnTrue() {
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void onLocationModeChanged_disabledByAdmin_shouldDisablePreference() {
mController.displayPreference(mScreen);
final EnforcedAdmin admin = mock(EnforcedAdmin.class);
doReturn(admin).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).isManagedProfileRestrictedByBase();
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setDisabledByAdmin(any());
verify(mPreference).setChecked(false);
}
@Test
public void onLocationModeChanged_locationOff_shouldDisablePreference() {
mController.displayPreference(mScreen);
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).isManagedProfileRestrictedByBase();
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_OFF, false);
verify(mPreference).setEnabled(false);
verify(mPreference).setChecked(false);
verify(mPreference).setSummary(R.string.switch_off_text);
}
@Test
public void onLocationModeChanged_locationOn_shouldEnablePreference() {
mController.displayPreference(mScreen);
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).isManagedProfileRestrictedByBase();
doReturn(true).when(mEnabler).isEnabled(anyInt());
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setEnabled(true);
verify(mPreference).setSummary(R.string.switch_on_text);
}
@Test
public void onLocationModeChanged_noRestriction_shouldCheckedPreference() {
mController.displayPreference(mScreen);
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).isManagedProfileRestrictedByBase();
doReturn(true).when(mEnabler).isEnabled(anyInt());
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setChecked(true);
}
@Test
public void onLocationModeChanged_hasRestriction_shouldCheckedPreference() {
mController.displayPreference(mScreen);
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(true).when(mEnabler).isManagedProfileRestrictedByBase();
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setChecked(false);
}
private void mockManagedProfile() {
final List<UserHandle> userProfiles = new ArrayList<>();
when(mUserHandle.getIdentifier()).thenReturn(5);
userProfiles.add(mUserHandle);
when(mUserManager.getUserProfiles()).thenReturn(userProfiles);
when(mUserManager.getUserHandle()).thenReturn(1);
when(mUserManager.getUserInfo(5))
.thenReturn(new UserInfo(5, "user 5", UserInfo.FLAG_MANAGED_PROFILE));
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.provider.Settings;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationModeBatterySavingPreferenceControllerTest {
@Test
public void getLocationMode_shouldReturnModeBatterySaving() {
final LocationModeBatterySavingPreferenceController controller =
new LocationModeBatterySavingPreferenceController(mock(Context.class),
new Lifecycle());
assertThat(controller.getLocationMode())
.isEqualTo(Settings.Secure.LOCATION_MODE_BATTERY_SAVING);
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.provider.Settings;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationModeHighAccuracyPreferenceControllerTest {
@Test
public void getLocationMode_shouldReturnModeHighAccuracy() {
final LocationModeHighAccuracyPreferenceController controller =
new LocationModeHighAccuracyPreferenceController(mock(Context.class),
new Lifecycle());
assertThat(controller.getLocationMode())
.isEqualTo(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY);
}
}

View File

@@ -0,0 +1,123 @@
/*
* 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 static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationModePreferenceControllerTest {
@Mock
private LocationSettings mFragment;
@Mock
private SettingsActivity mActivity;
@Mock
private Preference mPreference;
@Mock
private PreferenceScreen mScreen;
@Mock
private UserManager mUserManager;
private Context mContext;
private LocationModePreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
mController = new LocationModePreferenceController(mContext, mFragment, new Lifecycle());
when(mFragment.getActivity()).thenReturn(mActivity);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
}
@Test
public void onLocationModeChanged_locationOff_shouldDisablePreference() {
when(mUserManager.hasUserRestriction(any())).thenReturn(false);
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_OFF, false);
verify(mPreference).setEnabled(false);
}
@Test
public void onLocationModeChanged_restricted_shouldDisablePreference() {
when(mUserManager.hasUserRestriction(any())).thenReturn(true);
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setEnabled(false);
}
@Test
public void onLocationModeChanged_locationOnNotRestricted_shouldEnablePreference() {
when(mUserManager.hasUserRestriction(any())).thenReturn(false);
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setEnabled(true);
}
@Test
public void onLocationModeChanged_shouldUpdateSummary() {
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setSummary(anyInt());
}
@Test
public void handlePreferenceTreeClick_shouldStartLocationModeFragment() {
final Preference preference = new Preference(mContext);
preference.setKey(mController.getPreferenceKey());
mController.handlePreferenceTreeClick(preference);
verify(mActivity).startPreferencePanel(any(), eq(LocationMode.class.getName()), any(),
eq(R.string.location_mode_screen_title), any(), any(), anyInt());
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.RadioButtonPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config;
import org.robolectric.RuntimeEnvironment;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationModeRadioButtonPreferenceControllerTest {
@Mock
private RadioButtonPreference mPreference;
@Mock
private PreferenceScreen mScreen;
private Context mContext;
private LocationModeRadioButtonPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new LocationModeRadioButtonPreferenceControllerTestable(mContext);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
}
@Test
public void displayPreference_shouldAddClickListener() {
mController.displayPreference(mScreen);
verify(mPreference).setOnClickListener(mController);
}
@Test
public void onRadioButtonClicked_shouldSetLocationModeToOwnMode() {
mController.displayPreference(mScreen);
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF);
mController.onRadioButtonClicked(mPreference);
assertThat(Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF))
.isEqualTo(mController.getLocationMode());
}
@Test
public void onLocationModeChanged_otherModeSelected_shouldUncheckPreference() {
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setChecked(false);
}
@Test
public void onLocationModeChanged_ownModeSelected_shouldCheckPreference() {
mController.displayPreference(mScreen);
mController.onLocationModeChanged(mController.getLocationMode(), false);
verify(mPreference).setChecked(true);
}
@Test
public void onLocationModeChanged_locationOff_shouldDisablePreference() {
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_OFF, false);
verify(mPreference).setEnabled(false);
}
@Test
public void onLocationModeChanged_locationOn_shouldDisablePreference() {
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mPreference).setEnabled(true);
}
private class LocationModeRadioButtonPreferenceControllerTestable
extends LocationModeRadioButtonPreferenceController {
public LocationModeRadioButtonPreferenceControllerTestable(Context context) {
super(context, new Lifecycle());
}
@Override
public String getPreferenceKey() {
return "test";
}
@Override
protected int getLocationMode() {
return Settings.Secure.LOCATION_MODE_HIGH_ACCURACY;
}
}
}

View File

@@ -0,0 +1,47 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import android.content.Context;
import android.provider.Settings;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationModeSensorsOnlyPreferenceControllerTest {
@Test
public void getLocationMode_shouldReturnModeSensorsOnly() {
final LocationModeSensorsOnlyPreferenceController controller =
new LocationModeSensorsOnlyPreferenceController(mock(Context.class),
new Lifecycle());
assertThat(controller.getLocationMode())
.isEqualTo(Settings.Secure.LOCATION_MODE_SENSORS_ONLY);
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationServicePreferenceControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private LocationSettings mFragment;
@Mock
private PreferenceCategory mCategory;
@Mock
private PreferenceScreen mScreen;
@Mock
private SettingsInjector mSettingsInjector;
private Context mContext;
private LocationServicePreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mController = spy(new LocationServicePreferenceController(
mContext, mFragment, new Lifecycle(), mSettingsInjector));
final String key = mController.getPreferenceKey();
when(mScreen.findPreference(key)).thenReturn(mCategory);
when(mCategory.getKey()).thenReturn(key);
}
@Test
public void isAvailable_noInjectedSettings_shouldReturnFalse() {
doReturn(false).when(mSettingsInjector).hasInjectedSettings(anyInt());
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void isAvailable_hasInjectedSettings_shouldReturnFalse() {
doReturn(true).when(mSettingsInjector).hasInjectedSettings(anyInt());
assertThat(mController.isAvailable()).isTrue();
}
@Test
public void onResume_shouldRegisterListener() {
mController.onResume();
verify(mContext).registerReceiver(eq(mController.mInjectedSettingsReceiver),
eq(mController.INTENT_FILTER_INJECTED_SETTING_CHANGED));
}
@Test
public void onPause_shouldUnregisterListener() {
mController.onResume();
mController.onPause();
verify(mContext).unregisterReceiver(mController.mInjectedSettingsReceiver);
}
@Test
public void updateState_shouldRemoveAllAndAddInjectedSettings() {
final List<Preference> preferences = new ArrayList<>();
final Preference pref1 = new Preference(mContext);
pref1.setTitle("Title1");
final Preference pref2 = new Preference(mContext);
pref2.setTitle("Title2");
preferences.add(pref1);
preferences.add(pref2);
doReturn(preferences).when(mSettingsInjector)
.getInjectedSettings(any(Context.class), anyInt());
when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
mController.displayPreference(mScreen);
mController.updateState(mCategory);
verify(mCategory).removeAll();
verify(mCategory).addPreference(pref1);
verify(mCategory).addPreference(pref2);
}
@Test
public void onLocationModeChanged_shouldRequestReloadInjectedSettigns() {
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mSettingsInjector).reloadStatusMessages();
}
}

View File

@@ -0,0 +1,155 @@
/*
* 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 static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.ToggleSwitch;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class LocationSwitchBarControllerTest {
@Mock
private SwitchBar mSwitchBar;
@Mock
private ToggleSwitch mSwitch;
@Mock
private LocationEnabler mEnabler;
private Context mContext;
private LocationSwitchBarController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
ReflectionHelpers.setField(mSwitchBar, "mSwitch", mSwitch);
mController = spy(new LocationSwitchBarController(
mContext, mSwitchBar, new Lifecycle()));
ReflectionHelpers.setField(mController, "mLocationEnabler", mEnabler);
}
@Test
public void onStart_shouldShowSwitchBarAndAddOnSwitchChangeListener() {
mController.onStart();
verify(mSwitchBar).show();
verify(mSwitchBar).addOnSwitchChangeListener(mController);
}
@Test
public void onStop_shouldHideSwitchBarAndRemoveOnSwitchChangeListener() {
mController.onStart();
mController.onStop();
verify(mSwitchBar).hide();
verify(mSwitchBar).removeOnSwitchChangeListener(mController);
}
@Test
public void onSwitchChanged_switchChecked_shouldSetPreviousLocationMode() {
mController.onSwitchChanged(mSwitch, true);
verify(mEnabler).setLocationMode(
android.provider.Settings.Secure.LOCATION_MODE_PREVIOUS);
}
@Test
public void onSwitchChanged_switchUnchecked_shouldSetLocationModeOff() {
mController.onSwitchChanged(mSwitch, false);
verify(mEnabler).setLocationMode(android.provider.Settings.Secure.LOCATION_MODE_OFF);
}
@Test
public void onLocationModeChanged_hasEnforcedAdmin_shouldDisableSwitchByAdmin() {
final RestrictedLockUtils.EnforcedAdmin admin =
mock(RestrictedLockUtils.EnforcedAdmin.class);
doReturn(admin).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).hasShareLocationRestriction(anyInt());
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mSwitchBar).setDisabledByAdmin(admin);
}
@Test
public void onLocationModeChanged_Restricted_shouldDisableSwitch() {
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(true).when(mEnabler).hasShareLocationRestriction(anyInt());
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, true);
verify(mSwitchBar).setEnabled(false);
}
@Test
public void onLocationModeChanged_notRestricted_shouldEnableSwitch() {
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).hasShareLocationRestriction(anyInt());
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mSwitchBar).setEnabled(true);
}
@Test
public void onLocationModeChanged_locationOn_shouldCheckSwitch() {
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).hasShareLocationRestriction(anyInt());
when(mSwitch.isChecked()).thenReturn(false);
doReturn(true).when(mEnabler).isEnabled(anyInt());
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mSwitch).setChecked(true);
}
@Test
public void onLocationModeChanged_locationOff_shouldUncheckSwitch() {
doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt());
doReturn(false).when(mEnabler).hasShareLocationRestriction(anyInt());
when(mSwitch.isChecked()).thenReturn(true);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_OFF, false);
verify(mSwitch).setChecked(false);
}
}

View File

@@ -0,0 +1,176 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
import com.android.settings.applications.InstalledAppDetails;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.AppPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.location.RecentLocationApps;
import com.android.settingslib.location.RecentLocationApps.Request;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class RecentLocationRequestPreferenceControllerTest {
@Mock
private LocationSettings mFragment;
@Mock
private PreferenceCategory mCategory;
@Mock
private PreferenceScreen mScreen;
@Mock
private RecentLocationApps mRecentLocationApps;
private Context mContext;
private RecentLocationRequestPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mController = spy(new RecentLocationRequestPreferenceController(
mContext, mFragment, new Lifecycle(), mRecentLocationApps));
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mCategory);
final String key = mController.getPreferenceKey();
when(mCategory.getKey()).thenReturn(key);
when(mCategory.getContext()).thenReturn(mContext);
}
@Test
public void onLocationModeChanged_LocationOn_shouldEnablePreference() {
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false);
verify(mCategory).setEnabled(true);
}
@Test
public void onLocationModeChanged_LocationOff_shouldDisablePreference() {
mController.displayPreference(mScreen);
mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_OFF, false);
verify(mCategory).setEnabled(false);
}
@Test
public void updateState_noRecentRequest_shouldRemoveAllAndAddBanner() {
doReturn(new ArrayList<>()).when(mRecentLocationApps).getAppList();
mController.displayPreference(mScreen);
mController.updateState(mCategory);
verify(mCategory).removeAll();
verify(mCategory).addPreference(
argThat(titleMatches(mContext.getString(R.string.location_no_recent_apps))));
}
@Test
public void updateState_hasRecentRequest_shouldRemoveAllAndAddInjectedSettings() {
final List<RecentLocationApps.Request> requests = new ArrayList<>();
final Request req1 = mock(Request.class);
final Request req2 = mock(Request.class);
requests.add(req1);
requests.add(req2);
doReturn(requests).when(mRecentLocationApps).getAppList();
final String title = "testTitle";
final AppPreference preference = mock(AppPreference.class);
when(preference.getTitle()).thenReturn(title);
doReturn(preference).when(mController)
.createAppPreference(any(Context.class), any(Request.class));
mController.displayPreference(mScreen);
mController.updateState(mCategory);
verify(mCategory).removeAll();
verify(mCategory, times(2)).addPreference(argThat(titleMatches(title)));
}
@Test
public void createAppPreference_shouldAddClickListener() {
final Request request = mock(Request.class);
final AppPreference preference = mock(AppPreference.class);
doReturn(preference).when(mController)
.createAppPreference(any(Context.class));
mController.createAppPreference(mContext, request);
verify(preference).setOnPreferenceClickListener(
any(RecentLocationRequestPreferenceController.PackageEntryClickedListener.class));
}
@Test
public void onPreferenceClick_shouldLaunchAppDetails() {
final SettingsActivity activity = mock(SettingsActivity.class);
when(mFragment.getActivity()).thenReturn(activity);
final List<RecentLocationApps.Request> requests = new ArrayList<>();
final Request request = mock(Request.class);
requests.add(request);
doReturn(requests).when(mRecentLocationApps).getAppList();
final AppPreference preference = new AppPreference(mContext);
doReturn(preference).when(mController).createAppPreference(any(Context.class));
mController.displayPreference(mScreen);
mController.updateState(mCategory);
preference.performClick();
verify(activity).startPreferencePanelAsUser(any(), eq(InstalledAppDetails.class.getName()),
any(Bundle.class), anyInt(), any(), any());
}
private static ArgumentMatcher<Preference> titleMatches(String expected) {
return preference -> TextUtils.equals(expected, preference.getTitle());
}
}

View File

@@ -34,13 +34,12 @@ import org.robolectric.annotation.Config;
import java.util.List; import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class ScanningSettingsTest { public class ScanningSettingsTest {
private Context mContext; private Context mContext;
private ScanningSettings mSettings; private ScanningSettings mSettings;
@Before @Before
public void setUp() { public void setUp() {
mContext = RuntimeEnvironment.application; mContext = RuntimeEnvironment.application;

View File

@@ -0,0 +1,97 @@
/*
* 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 static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import com.android.settings.TestConfig;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION_O)
public class WifiScanningPreferenceControllerTest {
@Mock
private SwitchPreference mPreference;
private Context mContext;
private WifiScanningPreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = new WifiScanningPreferenceController(mContext);
when(mPreference.getKey()).thenReturn(mController.getPreferenceKey());
}
@Test
public void updateState_wifiScanningEnabled_shouldCheckedPreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1);
mController.updateState(mPreference);
verify(mPreference).setChecked(true);
}
@Test
public void updateState_wifiScanningDisabled_shouldUncheckedPreference() {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
mController.updateState(mPreference);
verify(mPreference).setChecked(false);
}
@Test
public void handlePreferenceTreeClick_checked_shouldEnableWifiScanning() {
when(mPreference.isChecked()).thenReturn(true);
mController.handlePreferenceTreeClick(mPreference);
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0)).isEqualTo(1);
}
@Test
public void handlePreferenceTreeClick_unchecked_shouldDisableWifiScanning() {
when(mPreference.isChecked()).thenReturn(false);
mController.handlePreferenceTreeClick(mPreference);
assertThat(Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 1)).isEqualTo(0);
}
}