Merge "Block location accuracy when DISALLOW_CONFIG_LOCATION is set." into pi-dev
diff --git a/src/com/android/settings/location/InjectedSetting.java b/src/com/android/settings/location/InjectedSetting.java
index e5f1e68..7eae872 100644
--- a/src/com/android/settings/location/InjectedSetting.java
+++ b/src/com/android/settings/location/InjectedSetting.java
@@ -22,7 +22,8 @@
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 @@
*/
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 @@
", iconId=" + iconId +
", userId=" + mUserHandle.getIdentifier() +
", settingsActivity='" + settingsActivity + '\'' +
+ ", userRestriction='" + userRestriction +
'}';
}
@@ -121,10 +110,13 @@
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 @@
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);
+ }
+ }
}
diff --git a/src/com/android/settings/location/LocationServicePreferenceController.java b/src/com/android/settings/location/LocationServicePreferenceController.java
index 0a6a5c1..a1d2069 100644
--- a/src/com/android/settings/location/LocationServicePreferenceController.java
+++ b/src/com/android/settings/location/LocationServicePreferenceController.java
@@ -25,6 +25,7 @@
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 @@
@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
diff --git a/src/com/android/settings/location/SettingsInjector.java b/src/com/android/settings/location/SettingsInjector.java
index dfa5143..2c6a4f3 100644
--- a/src/com/android/settings/location/SettingsInjector.java
+++ b/src/com/android/settings/location/SettingsInjector.java
@@ -20,6 +20,7 @@
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.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 @@
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 @@
*/
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;
}
diff --git a/src/com/android/settings/widget/RestrictedAppPreference.java b/src/com/android/settings/widget/RestrictedAppPreference.java
new file mode 100644
index 0000000..af6d8d1
--- /dev/null
+++ b/src/com/android/settings/widget/RestrictedAppPreference.java
@@ -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);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/location/InjectedSettingTest.java b/tests/robotests/src/com/android/settings/location/InjectedSettingTest.java
new file mode 100644
index 0000000..fb99958
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/location/InjectedSettingTest.java
@@ -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);
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java
index 195e1b4..099ef7d 100644
--- a/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/location/LocationServicePreferenceControllerTest.java
@@ -24,16 +24,25 @@
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.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 @@
private PreferenceScreen mScreen;
@Mock
private SettingsInjector mSettingsInjector;
+ @Mock
+ private DevicePolicyManager mDevicePolicyManager;
private Context mContext;
private LocationServicePreferenceController mController;
@@ -73,6 +86,9 @@
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 @@
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();
+ }
}