Merge "Block location accuracy when DISALLOW_CONFIG_LOCATION is set." into pi-dev

This commit is contained in:
Yueming Wang
2018-03-07 20:10:10 +00:00
committed by Android (Google) Code Review
6 changed files with 347 additions and 42 deletions

View File

@@ -22,7 +22,8 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.Immutable;
import com.android.internal.util.Preconditions;
import java.util.Objects;
/**
* Specifies a setting that is being injected into Settings > Location > Location services.
@@ -65,32 +66,19 @@ class InjectedSetting {
*/
public final String settingsActivity;
private InjectedSetting(String packageName, String className,
String title, int iconId, UserHandle userHandle, String settingsActivity) {
this.packageName = Preconditions.checkNotNull(packageName, "packageName");
this.className = Preconditions.checkNotNull(className, "className");
this.title = Preconditions.checkNotNull(title, "title");
this.iconId = iconId;
this.mUserHandle = userHandle;
this.settingsActivity = Preconditions.checkNotNull(settingsActivity);
}
/**
* Returns a new instance, or null.
* The user restriction associated with this setting.
*/
public static InjectedSetting newInstance(String packageName, String className,
String title, int iconId, UserHandle userHandle, String settingsActivity) {
if (packageName == null || className == null ||
TextUtils.isEmpty(title) || TextUtils.isEmpty(settingsActivity)) {
if (Log.isLoggable(SettingsInjector.TAG, Log.WARN)) {
Log.w(SettingsInjector.TAG, "Illegal setting specification: package="
+ packageName + ", class=" + className
+ ", title=" + title + ", settingsActivity=" + settingsActivity);
}
return null;
}
return new InjectedSetting(packageName, className, title, iconId, userHandle,
settingsActivity);
public final String userRestriction;
private InjectedSetting(Builder builder) {
this.packageName = builder.mPackageName;
this.className = builder.mClassName;
this.title = builder.mTitle;
this.iconId = builder.mIconId;
this.mUserHandle = builder.mUserHandle;
this.settingsActivity = builder.mSettingsActivity;
this.userRestriction = builder.mUserRestriction;
}
@Override
@@ -102,6 +90,7 @@ class InjectedSetting {
", iconId=" + iconId +
", userId=" + mUserHandle.getIdentifier() +
", settingsActivity='" + settingsActivity + '\'' +
", userRestriction='" + userRestriction +
'}';
}
@@ -121,10 +110,13 @@ class InjectedSetting {
InjectedSetting that = (InjectedSetting) o;
return packageName.equals(that.packageName) && className.equals(that.className)
&& title.equals(that.title) && iconId == that.iconId
&& mUserHandle.equals(that.mUserHandle)
&& settingsActivity.equals(that.settingsActivity);
return Objects.equals(packageName, that.packageName)
&& Objects.equals(className, that.className)
&& Objects.equals(title, that.title)
&& Objects.equals(iconId, that.iconId)
&& Objects.equals(mUserHandle, that.mUserHandle)
&& Objects.equals(settingsActivity, that.settingsActivity)
&& Objects.equals(userRestriction, that.userRestriction);
}
@Override
@@ -133,8 +125,67 @@ class InjectedSetting {
result = 31 * result + className.hashCode();
result = 31 * result + title.hashCode();
result = 31 * result + iconId;
result = 31 * result + mUserHandle.hashCode();
result = 31 * result + (mUserHandle == null ? 0 : mUserHandle.hashCode());
result = 31 * result + settingsActivity.hashCode();
result = 31 * result + (userRestriction == null ? 0 : userRestriction.hashCode());
return result;
}
public static class Builder {
private String mPackageName;
private String mClassName;
private String mTitle;
private int mIconId;
private UserHandle mUserHandle;
private String mSettingsActivity;
private String mUserRestriction;
public Builder setPackageName(String packageName) {
mPackageName = packageName;
return this;
}
public Builder setClassName(String className) {
mClassName = className;
return this;
}
public Builder setTitle(String title) {
mTitle = title;
return this;
}
public Builder setIconId(int iconId) {
mIconId = iconId;
return this;
}
public Builder setUserHandle(UserHandle userHandle) {
mUserHandle = userHandle;
return this;
}
public Builder setSettingsActivity(String settingsActivity) {
mSettingsActivity = settingsActivity;
return this;
}
public Builder setUserRestriction(String userRestriction) {
mUserRestriction = userRestriction;
return this;
}
public InjectedSetting build() {
if (mPackageName == null || mClassName == null || TextUtils.isEmpty(mTitle)
|| TextUtils.isEmpty(mSettingsActivity)) {
if (Log.isLoggable(SettingsInjector.TAG, Log.WARN)) {
Log.w(SettingsInjector.TAG, "Illegal setting specification: package="
+ mPackageName + ", class=" + mClassName
+ ", title=" + mTitle + ", settingsActivity=" + mSettingsActivity);
}
return null;
}
return new InjectedSetting(this);
}
}
}

View File

@@ -25,6 +25,7 @@ import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import android.util.Log;
import com.android.settings.widget.RestrictedAppPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
@@ -88,7 +89,13 @@ public class LocationServicePreferenceController extends LocationBasePreferenceC
@Override
public void updateState(Preference preference) {
mCategoryLocationServices.removeAll();
LocationSettings.addPreferencesSorted(getLocationServices(), mCategoryLocationServices);
final List<Preference> prefs = getLocationServices();
for (Preference pref : prefs) {
if (pref instanceof RestrictedAppPreference) {
((RestrictedAppPreference) pref).checkRestrictionAndSetDisabled();
}
}
LocationSettings.addPreferencesSorted(prefs, mCategoryLocationServices);
}
@Override

View File

@@ -20,6 +20,7 @@ import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
@@ -37,11 +38,14 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.IconDrawableFactory;
import android.util.Log;
import android.util.Xml;
import com.android.settings.widget.AppPreference;
import com.android.settings.widget.RestrictedAppPreference;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -215,12 +219,21 @@ class SettingsInjector {
sa.getResourceId(android.R.styleable.SettingInjectorService_icon, 0);
final String settingsActivity =
sa.getString(android.R.styleable.SettingInjectorService_settingsActivity);
final String userRestriction = sa.getString(
android.R.styleable.SettingInjectorService_userRestriction);
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "parsed title: " + title + ", iconId: " + iconId
+ ", settingsActivity: " + settingsActivity);
}
return InjectedSetting.newInstance(packageName, className,
title, iconId, userHandle, settingsActivity);
return new InjectedSetting.Builder()
.setPackageName(packageName)
.setClassName(className)
.setTitle(title)
.setIconId(iconId)
.setUserHandle(userHandle)
.setSettingsActivity(settingsActivity)
.setUserRestriction(userRestriction)
.build();
} finally {
sa.recycle();
}
@@ -290,15 +303,26 @@ class SettingsInjector {
*/
private Preference addServiceSetting(Context prefContext, List<Preference> prefs,
InjectedSetting info) {
PackageManager pm = mContext.getPackageManager();
Drawable appIcon = pm.getDrawable(info.packageName, info.iconId, null);
Drawable icon = pm.getUserBadgedIcon(appIcon, info.mUserHandle);
Preference pref = new AppPreference(prefContext);
final PackageManager pm = mContext.getPackageManager();
Drawable appIcon = null;
try {
final PackageItemInfo itemInfo = new PackageItemInfo();
itemInfo.icon = info.iconId;
itemInfo.packageName = info.packageName;
final ApplicationInfo appInfo = pm.getApplicationInfo(info.packageName,
PackageManager.GET_META_DATA);
appIcon = IconDrawableFactory.newInstance(mContext)
.getBadgedIcon(itemInfo, appInfo, info.mUserHandle.getIdentifier());
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Can't get ApplicationInfo for " + info.packageName, e);
}
Preference pref = TextUtils.isEmpty(info.userRestriction)
? new AppPreference(prefContext)
: new RestrictedAppPreference(prefContext, info.userRestriction);
pref.setTitle(info.title);
pref.setSummary(null);
pref.setIcon(icon);
pref.setIcon(appIcon);
pref.setOnPreferenceClickListener(new ServiceSettingClickedListener(info));
prefs.add(pref);
return pref;
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright (C) 2018 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.widget;
import android.content.Context;
import android.os.UserHandle;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceViewHolder;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreferenceHelper;
/**
* {@link AppPreference} that implements user restriction utilities using
* {@link com.android.settingslib.RestrictedPreferenceHelper}.
* Used to show policy transparency on {@link AppPreference}.
*/
public class RestrictedAppPreference extends AppPreference {
private RestrictedPreferenceHelper mHelper;
private String userRestriction;
public RestrictedAppPreference(Context context) {
super(context);
initialize(null, null);
}
public RestrictedAppPreference(Context context, String userRestriction) {
super(context);
initialize(null, userRestriction);
}
public RestrictedAppPreference(Context context, AttributeSet attrs, String userRestriction) {
super(context, attrs);
initialize(attrs, userRestriction);
}
private void initialize(AttributeSet attrs, String userRestriction) {
setWidgetLayoutResource(R.layout.restricted_icon);
mHelper = new RestrictedPreferenceHelper(getContext(), this, attrs);
this.userRestriction = userRestriction;
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mHelper.onBindViewHolder(holder);
final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
if (restrictedIcon != null) {
restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
}
}
@Override
public void performClick() {
if (!mHelper.performClick()) {
super.performClick();
}
}
@Override
public void setEnabled(boolean enabled) {
if (isDisabledByAdmin() && enabled) {
return;
}
super.setEnabled(enabled);
}
public void setDisabledByAdmin(RestrictedLockUtils.EnforcedAdmin admin) {
if (mHelper.setDisabledByAdmin(admin)) {
notifyChanged();
}
}
public boolean isDisabledByAdmin() {
return mHelper.isDisabledByAdmin();
}
public void useAdminDisabledSummary(boolean useSummary) {
mHelper.useAdminDisabledSummary(useSummary);
}
@Override
protected void onAttachedToHierarchy(PreferenceManager preferenceManager) {
mHelper.onAttachedToHierarchy();
super.onAttachedToHierarchy(preferenceManager);
}
public void checkRestrictionAndSetDisabled() {
if (TextUtils.isEmpty(userRestriction)) {
return;
}
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
public void checkRestrictionAndSetDisabled(String userRestriction) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, UserHandle.myUserId());
}
public void checkRestrictionAndSetDisabled(String userRestriction, int userId) {
mHelper.checkRestrictionAndSetDisabled(userRestriction, userId);
}
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2018 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 com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(SettingsRobolectricTestRunner.class)
public final class InjectedSettingTest {
private static final String TEST_STRING = "test";
@Test
public void buildWithoutPackageName_ShouldReturnNull() {
assertThat(((new InjectedSetting.Builder())
.setClassName(TEST_STRING)
.setTitle(TEST_STRING)
.setSettingsActivity(TEST_STRING).build())).isNull();
}
private InjectedSetting getTestSetting() {
return new InjectedSetting.Builder()
.setPackageName(TEST_STRING)
.setClassName(TEST_STRING)
.setTitle(TEST_STRING)
.setSettingsActivity(TEST_STRING).build();
}
@Test
public void testEquals() {
InjectedSetting setting1 = getTestSetting();
InjectedSetting setting2 = getTestSetting();
assertThat(setting1).isEqualTo(setting2);
}
@Test
public void testHashCode() {
InjectedSetting setting = getTestSetting();
assertThat(setting.hashCode()).isEqualTo(1225314048);
}
}

View File

@@ -24,16 +24,25 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.admin.DevicePolicyManager;
import android.arch.lifecycle.LifecycleOwner;
import android.content.ComponentName;
import android.content.Context;
import android.os.UserHandle;
import android.os.UserManager;
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.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.widget.RestrictedAppPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,11 +50,13 @@ import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(
shadows = {
ShadowUserManager.class
})
public class LocationServicePreferenceControllerTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -56,6 +67,8 @@ public class LocationServicePreferenceControllerTest {
private PreferenceScreen mScreen;
@Mock
private SettingsInjector mSettingsInjector;
@Mock
private DevicePolicyManager mDevicePolicyManager;
private Context mContext;
private LocationServicePreferenceController mController;
@@ -73,6 +86,9 @@ public class LocationServicePreferenceControllerTest {
final String key = mController.getPreferenceKey();
when(mScreen.findPreference(key)).thenReturn(mCategory);
when(mCategory.getKey()).thenReturn(key);
when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE))
.thenReturn(mDevicePolicyManager);
}
@Test
@@ -132,4 +148,33 @@ public class LocationServicePreferenceControllerTest {
verify(mSettingsInjector).reloadStatusMessages();
}
@Test
public void withUserRestriction_shouldDisableLocationAccuracy() {
final List<Preference> preferences = new ArrayList<>();
final RestrictedAppPreference pref = new RestrictedAppPreference(mContext,
UserManager.DISALLOW_CONFIG_LOCATION);
pref.setTitle("Location Accuracy");
preferences.add(pref);
doReturn(preferences).when(mSettingsInjector)
.getInjectedSettings(any(Context.class), anyInt());
int userId = UserHandle.myUserId();
List<UserManager.EnforcingUser> enforcingUsers = new ArrayList<>();
enforcingUsers.add(new UserManager.EnforcingUser(userId,
UserManager.RESTRICTION_SOURCE_DEVICE_OWNER));
ComponentName componentName = new ComponentName("test", "test");
// Ensure that RestrictedLockUtils.checkIfRestrictionEnforced doesn't return null.
ShadowUserManager.getShadow().setUserRestrictionSources(
UserManager.DISALLOW_CONFIG_LOCATION,
UserHandle.of(userId),
enforcingUsers);
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(componentName);
mController.displayPreference(mScreen);
mController.updateState(mCategory);
assertThat(pref.isEnabled()).isFalse();
assertThat(pref.isDisabledByAdmin()).isTrue();
}
}