Merge "Add ability to show/hide items for Special Access."
diff --git a/res/layout/data_usage_bytes_editor.xml b/res/layout/data_usage_bytes_editor.xml
index af2d59b..2878c3e 100644
--- a/res/layout/data_usage_bytes_editor.xml
+++ b/res/layout/data_usage_bytes_editor.xml
@@ -37,6 +37,7 @@
android:id="@+id/size_spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical" />
+ android:layout_gravity="center_vertical"
+ android:entries="@array/bytes_picker_sizes" />
</LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a809c78..3dc342b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -8505,6 +8505,11 @@
<!-- Text for the setting on whether you can type text into notifications without unlocking the device. -->
<string name="lockscreen_remote_input">If device is locked, prevent typing replies or other text in notifications</string>
+ <string-array name="bytes_picker_sizes" translatable="false">
+ <item>@*android:string/megabyteShort</item>
+ <item>@*android:string/gigabyteShort</item>
+ </string-array>
+
<!-- [CHAR LIMIT=30] Label for setting to control the default spell checker -->
<string name="default_spell_checker">Default spell checker</string>
diff --git a/res/xml/security_settings_v2.xml b/res/xml/security_settings_v2.xml
index 155ee70..30e829d 100644
--- a/res/xml/security_settings_v2.xml
+++ b/res/xml/security_settings_v2.xml
@@ -28,6 +28,22 @@
android:title="@string/security_status_title" />
<!-- TODO Need security section -->
+ <PreferenceCategory
+ android:key="security_category"
+ android:title="@string/lock_settings_title">
+
+ <!-- security_settings_chooser -->
+ <com.android.settings.widget.GearPreference
+ android:key="unlock_set_or_change"
+ android:title="@string/unlock_set_unlock_launch_picker_title"
+ android:summary="@string/unlock_set_unlock_mode_none"
+ settings:keywords="@string/keywords_lockscreen" />
+
+ <Preference android:key="lockscreen_preferences"
+ android:title="@string/lockscreen_settings_title"
+ android:fragment="com.android.settings.security.LockscreenDashboardFragment"/>
+
+ </PreferenceCategory>
<!-- security_settings_misc.xml -->
<PreferenceCategory
diff --git a/src/com/android/settings/dashboard/DashboardFragment.java b/src/com/android/settings/dashboard/DashboardFragment.java
index 3e1e881..6a88a38 100644
--- a/src/com/android/settings/dashboard/DashboardFragment.java
+++ b/src/com/android/settings/dashboard/DashboardFragment.java
@@ -54,7 +54,7 @@
SummaryLoader.SummaryConsumer {
private static final String TAG = "DashboardFragment";
- private final Map<Class, AbstractPreferenceController> mPreferenceControllers =
+ private final Map<Class, List<AbstractPreferenceController>> mPreferenceControllers =
new ArrayMap<>();
private final Set<String> mDashboardTilePrefKeys = new ArraySet<>();
@@ -156,14 +156,17 @@
@Override
public boolean onPreferenceTreeClick(Preference preference) {
- Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();
+ Collection<List<AbstractPreferenceController>> controllers =
+ mPreferenceControllers.values();
// If preference contains intent, log it before handling.
mMetricsFeatureProvider.logDashboardStartIntent(
getContext(), preference.getIntent(), getMetricsCategory());
// Give all controllers a chance to handle click.
- for (AbstractPreferenceController controller : controllers) {
- if (controller.handlePreferenceTreeClick(preference)) {
- return true;
+ for (List<AbstractPreferenceController> controllerList : controllers) {
+ for (AbstractPreferenceController controller : controllerList) {
+ if (controller.handlePreferenceTreeClick(preference)) {
+ return true;
+ }
}
}
return super.onPreferenceTreeClick(preference);
@@ -189,12 +192,23 @@
protected abstract int getPreferenceScreenResId();
protected <T extends AbstractPreferenceController> T getPreferenceController(Class<T> clazz) {
- AbstractPreferenceController controller = mPreferenceControllers.get(clazz);
- return (T) controller;
+ List<AbstractPreferenceController> controllerList = mPreferenceControllers.get(clazz);
+ if (controllerList != null) {
+ if (controllerList.size() > 1) {
+ Log.w(TAG, "Multiple controllers of Class " + clazz.getSimpleName()
+ + " found, returning first one.");
+ }
+ return (T) controllerList.get(0);
+ }
+
+ return null;
}
protected void addPreferenceController(AbstractPreferenceController controller) {
- mPreferenceControllers.put(controller.getClass(), controller);
+ if (mPreferenceControllers.get(controller.getClass()) == null) {
+ mPreferenceControllers.put(controller.getClass(), new ArrayList<>());
+ }
+ mPreferenceControllers.get(controller.getClass()).add(controller);
}
/**
@@ -249,31 +263,32 @@
}
addPreferencesFromResource(resId);
final PreferenceScreen screen = getPreferenceScreen();
- Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();
- for (AbstractPreferenceController controller : controllers) {
- controller.displayPreference(screen);
- }
+ mPreferenceControllers.values().stream().flatMap(Collection::stream).forEach(
+ controller -> controller.displayPreference(screen));
}
/**
* Update state of each preference managed by PreferenceController.
*/
protected void updatePreferenceStates() {
- Collection<AbstractPreferenceController> controllers = mPreferenceControllers.values();
final PreferenceScreen screen = getPreferenceScreen();
- for (AbstractPreferenceController controller : controllers) {
- if (!controller.isAvailable()) {
- continue;
- }
- final String key = controller.getPreferenceKey();
+ Collection<List<AbstractPreferenceController>> controllerLists =
+ mPreferenceControllers.values();
+ for (List<AbstractPreferenceController> controllerList : controllerLists) {
+ for (AbstractPreferenceController controller : controllerList) {
+ if (!controller.isAvailable()) {
+ continue;
+ }
+ final String key = controller.getPreferenceKey();
- final Preference preference = screen.findPreference(key);
- if (preference == null) {
- Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
- key, controller.getClass().getSimpleName()));
- continue;
+ final Preference preference = screen.findPreference(key);
+ if (preference == null) {
+ Log.d(TAG, String.format("Cannot find preference with key %s in Controller %s",
+ key, controller.getClass().getSimpleName()));
+ continue;
+ }
+ controller.updateState(preference);
}
- controller.updateState(preference);
}
}
diff --git a/src/com/android/settings/deviceinfo/StorageItemPreference.java b/src/com/android/settings/deviceinfo/StorageItemPreference.java
index d0114e3..3dcf935 100644
--- a/src/com/android/settings/deviceinfo/StorageItemPreference.java
+++ b/src/com/android/settings/deviceinfo/StorageItemPreference.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.res.Resources;
-import android.icu.util.MeasureUnit;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
@@ -52,7 +51,7 @@
FileSizeFormatter.formatFileSize(
getContext(),
size,
- MeasureUnit.GIGABYTE,
+ getGigabyteSuffix(getContext().getResources()),
FileSizeFormatter.GIGABYTE_IN_BYTES));
if (total == 0) {
mProgressPercent = 0;
@@ -76,4 +75,8 @@
updateProgressBar();
super.onBindViewHolder(view);
}
+
+ private static int getGigabyteSuffix(Resources res) {
+ return res.getIdentifier("gigabyteShort", "string", "android");
+ }
}
diff --git a/src/com/android/settings/security/SecuritySettingsV2.java b/src/com/android/settings/security/SecuritySettingsV2.java
index 91a8cc7..002e447 100644
--- a/src/com/android/settings/security/SecuritySettingsV2.java
+++ b/src/com/android/settings/security/SecuritySettingsV2.java
@@ -41,7 +41,7 @@
import com.android.settings.search.SearchIndexableRaw;
import com.android.settings.security.screenlock.ScreenLockSettings;
import com.android.settings.security.trustagent.ManageTrustAgentsPreferenceController;
-import com.android.settings.security.trustagent.TrustAgentManager;
+import com.android.settings.security.trustagent.TrustAgentListPreferenceController;
import com.android.settings.widget.GearPreference;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedPreference;
@@ -58,8 +58,6 @@
private static final String TAG = "SecuritySettingsV2";
- private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";
-
// Lock Settings
private static final String KEY_UNLOCK_SET_OR_CHANGE = "unlock_set_or_change";
private static final String KEY_UNLOCK_SET_OR_CHANGE_PROFILE = "unlock_set_or_change_profile";
@@ -73,16 +71,13 @@
private static final String KEY_LOCATION = "location";
private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST = 123;
- private static final int CHANGE_TRUST_AGENT_SETTINGS = 126;
+ public static final int CHANGE_TRUST_AGENT_SETTINGS = 126;
private static final int SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE = 127;
private static final int UNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 128;
private static final int UNIFY_LOCK_CONFIRM_PROFILE_REQUEST = 129;
private static final int UNUNIFY_LOCK_CONFIRM_DEVICE_REQUEST = 130;
private static final String TAG_UNIFICATION_DIALOG = "unification_dialog";
- // Misc Settings
- private static final String KEY_TRUST_AGENT = "trust_agent";
-
// Security status
private static final String KEY_SECURITY_STATUS = "security_status";
private static final String SECURITY_STATUS_KEY_PREFIX = "security_status_";
@@ -101,7 +96,6 @@
private DashboardFeatureProvider mDashboardFeatureProvider;
private DevicePolicyManager mDPM;
private SecurityFeatureProvider mSecurityFeatureProvider;
- private TrustAgentManager mTrustAgentManager;
private UserManager mUm;
private ChooseLockSettingsHelper mChooseLockSettingsHelper;
@@ -111,8 +105,6 @@
private SwitchPreference mVisiblePatternProfile;
private RestrictedSwitchPreference mUnifyProfile;
- private Intent mTrustAgentClickIntent;
-
private int mProfileChallengeUserId;
private String mCurrentDevicePassword;
@@ -127,6 +119,7 @@
private ScreenPinningPreferenceController mScreenPinningPreferenceController;
private SimLockPreferenceController mSimLockPreferenceController;
private ShowPasswordPreferenceController mShowPasswordPreferenceController;
+ private TrustAgentListPreferenceController mTrustAgentListPreferenceController;
@Override
public int getMetricsCategory() {
@@ -145,7 +138,7 @@
mDashboardFeatureProvider = FeatureFactory.getFactory(context)
.getDashboardFeatureProvider(context);
- mTrustAgentManager = mSecurityFeatureProvider.getTrustAgentManager();
+ mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
}
@Override
@@ -172,21 +165,11 @@
mShowPasswordPreferenceController = new ShowPasswordPreferenceController(context);
mEncryptionStatusPreferenceController = new EncryptionStatusPreferenceController(
context, PREF_KEY_ENCRYPTION_SECURITY_PAGE);
+ mTrustAgentListPreferenceController = new TrustAgentListPreferenceController(getActivity(),
+ this /* host */, getLifecycle());
return null;
}
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- mChooseLockSettingsHelper = new ChooseLockSettingsHelper(getActivity());
-
- if (savedInstanceState != null
- && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
- mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
- }
- }
-
private static int getResIdForLockUnlockScreen(LockPatternUtils lockPatternUtils,
ManagedLockPasswordProvider managedPasswordProvider, int userId) {
final boolean isMyUser = userId == MY_USER_ID;
@@ -237,6 +220,7 @@
}
addPreferencesFromResource(R.xml.security_settings_v2);
root = getPreferenceScreen();
+ mTrustAgentListPreferenceController.displayPreference(root);
// Add options for lock/unlock screen
final int resid = getResIdForLockUnlockScreen(mLockPatternUtils,
@@ -272,7 +256,6 @@
mProfileChallengeUserId);
}
}
-
Preference unlockSetOrChange = findPreference(KEY_UNLOCK_SET_OR_CHANGE);
if (unlockSetOrChange instanceof GearPreference) {
((GearPreference) unlockSetOrChange).setOnGearClickListener(this);
@@ -284,7 +267,6 @@
root.findPreference(KEY_SECURITY_CATEGORY);
if (securityCategory != null) {
maybeAddFingerprintPreference(securityCategory, UserHandle.myUserId());
- addTrustAgentSettings(securityCategory);
setLockscreenPreferencesSummary(securityCategory);
}
@@ -379,34 +361,6 @@
}
}
- // Return the number of trust agents being added
- private int addTrustAgentSettings(PreferenceGroup securityCategory) {
- final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID);
- final List<TrustAgentManager.TrustAgentComponentInfo> agents =
- mTrustAgentManager.getActiveTrustAgents(getActivity(), mLockPatternUtils);
- for (TrustAgentManager.TrustAgentComponentInfo agent : agents) {
- final RestrictedPreference trustAgentPreference =
- new RestrictedPreference(securityCategory.getContext());
- trustAgentPreference.setKey(KEY_TRUST_AGENT);
- trustAgentPreference.setTitle(agent.title);
- trustAgentPreference.setSummary(agent.summary);
- // Create intent for this preference.
- Intent intent = new Intent();
- intent.setComponent(agent.componentName);
- intent.setAction(Intent.ACTION_MAIN);
- trustAgentPreference.setIntent(intent);
- // Add preference to the settings menu.
- securityCategory.addPreference(trustAgentPreference);
-
- trustAgentPreference.setDisabledByAdmin(agent.admin);
- if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) {
- trustAgentPreference.setEnabled(false);
- trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
- }
- }
- return agents.size();
- }
-
@Override
public void onGearClick(GearPreference p) {
if (KEY_UNLOCK_SET_OR_CHANGE.equals(p.getKey())) {
@@ -415,14 +369,6 @@
}
@Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- if (mTrustAgentClickIntent != null) {
- outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent);
- }
- }
-
- @Override
public void onResume() {
super.onResume();
@@ -445,7 +391,7 @@
final Preference encryptionStatusPref = getPreferenceScreen().findPreference(
mEncryptionStatusPreferenceController.getPreferenceKey());
mEncryptionStatusPreferenceController.updateState(encryptionStatusPref);
-
+ mTrustAgentListPreferenceController.onResume();
mLocationController.updateSummary();
}
@@ -465,6 +411,9 @@
@Override
public boolean onPreferenceTreeClick(Preference preference) {
+ if (mTrustAgentListPreferenceController.handlePreferenceTreeClick(preference)) {
+ return true;
+ }
final String key = preference.getKey();
if (KEY_UNLOCK_SET_OR_CHANGE.equals(key)) {
// TODO(b/35930129): Remove once existing password can be passed into vold directly.
@@ -491,17 +440,6 @@
startFragment(this, ChooseLockGeneric.ChooseLockGenericFragment.class.getName(),
R.string.lock_settings_picker_title_profile,
SET_OR_CHANGE_LOCK_METHOD_REQUEST_PROFILE, extras);
- } else if (KEY_TRUST_AGENT.equals(key)) {
- ChooseLockSettingsHelper helper =
- new ChooseLockSettingsHelper(this.getActivity(), this);
- mTrustAgentClickIntent = preference.getIntent();
- boolean confirmationLaunched = helper.launchConfirmationActivity(
- CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle());
- if (!confirmationLaunched && mTrustAgentClickIntent != null) {
- // If this returns false, it means no password confirmation is required.
- startActivity(mTrustAgentClickIntent);
- mTrustAgentClickIntent = null;
- }
} else {
// If we didn't handle it, let preferences handle it.
return super.onPreferenceTreeClick(preference);
@@ -516,10 +454,7 @@
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == CHANGE_TRUST_AGENT_SETTINGS && resultCode == Activity.RESULT_OK) {
- if (mTrustAgentClickIntent != null) {
- startActivity(mTrustAgentClickIntent);
- mTrustAgentClickIntent = null;
- }
+ mTrustAgentListPreferenceController.handleActivityResult(resultCode);
return;
} else if (requestCode == UNIFY_LOCK_CONFIRM_DEVICE_REQUEST
&& resultCode == Activity.RESULT_OK) {
@@ -760,15 +695,9 @@
@Override
public List<String> getNonIndexableKeys(Context context) {
final List<String> keys = super.getNonIndexableKeys(context);
- final LockPatternUtils lockPatternUtils = new LockPatternUtils(context);
new SimLockPreferenceController(context).updateNonIndexableKeys(keys);
- // TrustAgent settings disappear when the user has no primary security.
- if (!lockPatternUtils.isSecure(MY_USER_ID)) {
- keys.add(KEY_TRUST_AGENT);
- }
-
if (!(new EnterprisePrivacyPreferenceController(context))
.isAvailable()) {
keys.add(KEY_ENTERPRISE_PRIVACY);
diff --git a/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java b/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java
new file mode 100644
index 0000000..d99757b
--- /dev/null
+++ b/src/com/android/settings/security/trustagent/TrustAgentListPreferenceController.java
@@ -0,0 +1,172 @@
+/*
+ * 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.security.trustagent;
+
+import android.app.Activity;
+import android.content.Intent;
+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 android.text.TextUtils;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.R;
+import com.android.settings.overlay.FeatureFactory;
+import com.android.settings.password.ChooseLockSettingsHelper;
+import com.android.settings.security.SecurityFeatureProvider;
+import com.android.settings.security.SecuritySettingsV2;
+import com.android.settingslib.RestrictedPreference;
+import com.android.settingslib.core.AbstractPreferenceController;
+import com.android.settingslib.core.lifecycle.Lifecycle;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnCreate;
+import com.android.settingslib.core.lifecycle.events.OnResume;
+import com.android.settingslib.core.lifecycle.events.OnSaveInstanceState;
+
+import java.util.List;
+
+public class TrustAgentListPreferenceController extends AbstractPreferenceController
+ implements LifecycleObserver, OnSaveInstanceState, OnCreate, OnResume {
+
+ private static final String TRUST_AGENT_CLICK_INTENT = "trust_agent_click_intent";
+ @VisibleForTesting
+ static final String PREF_KEY_TRUST_AGENT = "trust_agent";
+ @VisibleForTesting
+ static final String PREF_KEY_SECURITY_CATEGORY = "security_category";
+ private static final int MY_USER_ID = UserHandle.myUserId();
+
+ private final LockPatternUtils mLockPatternUtils;
+ private final TrustAgentManager mTrustAgentManager;
+ private final Activity mActivity;
+ private final SecuritySettingsV2 mHost;
+
+ private Intent mTrustAgentClickIntent;
+ private PreferenceCategory mSecurityCategory;
+
+ public TrustAgentListPreferenceController(Activity activity, SecuritySettingsV2 host,
+ Lifecycle lifecycle) {
+ super(activity);
+ final SecurityFeatureProvider provider = FeatureFactory.getFactory(activity)
+ .getSecurityFeatureProvider();
+ mActivity = activity;
+ mHost = host;
+ mLockPatternUtils = provider.getLockPatternUtils(activity);
+ mTrustAgentManager = provider.getTrustAgentManager();
+ if (lifecycle != null) {
+ lifecycle.addObserver(this);
+ }
+ }
+
+ @Override
+ public boolean isAvailable() {
+ return true;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return PREF_KEY_TRUST_AGENT;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mSecurityCategory = (PreferenceCategory) screen.findPreference(PREF_KEY_SECURITY_CATEGORY);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ if (savedInstanceState != null
+ && savedInstanceState.containsKey(TRUST_AGENT_CLICK_INTENT)) {
+ mTrustAgentClickIntent = savedInstanceState.getParcelable(TRUST_AGENT_CLICK_INTENT);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ if (mTrustAgentClickIntent != null) {
+ outState.putParcelable(TRUST_AGENT_CLICK_INTENT, mTrustAgentClickIntent);
+ }
+ }
+
+ @Override
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+ return super.handlePreferenceTreeClick(preference);
+ }
+ final ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(mActivity, mHost);
+ mTrustAgentClickIntent = preference.getIntent();
+ boolean confirmationLaunched = helper.launchConfirmationActivity(
+ SecuritySettingsV2.CHANGE_TRUST_AGENT_SETTINGS, preference.getTitle());
+
+ if (!confirmationLaunched && mTrustAgentClickIntent != null) {
+ // If this returns false, it means no password confirmation is required.
+ mHost.startActivity(mTrustAgentClickIntent);
+ mTrustAgentClickIntent = null;
+ }
+ return true;
+ }
+
+ @Override
+ public void onResume() {
+ if (mSecurityCategory == null) {
+ return;
+ }
+ // First remove all old trust agents.
+ while (true) {
+ final Preference oldAgent = mSecurityCategory.findPreference(PREF_KEY_TRUST_AGENT);
+ if (oldAgent == null) {
+ break;
+ } else {
+ mSecurityCategory.removePreference(oldAgent);
+ }
+ }
+ // Then add new ones.
+ final boolean hasSecurity = mLockPatternUtils.isSecure(MY_USER_ID);
+ final List<TrustAgentManager.TrustAgentComponentInfo> agents =
+ mTrustAgentManager.getActiveTrustAgents(mContext, mLockPatternUtils);
+ if (agents == null) {
+ return;
+ }
+ for (TrustAgentManager.TrustAgentComponentInfo agent : agents) {
+ final RestrictedPreference trustAgentPreference =
+ new RestrictedPreference(mSecurityCategory.getContext());
+ trustAgentPreference.setKey(PREF_KEY_TRUST_AGENT);
+ trustAgentPreference.setTitle(agent.title);
+ trustAgentPreference.setSummary(agent.summary);
+ // Create intent for this preference.
+ trustAgentPreference.setIntent(new Intent(Intent.ACTION_MAIN)
+ .setComponent(agent.componentName));
+ trustAgentPreference.setDisabledByAdmin(agent.admin);
+ if (!trustAgentPreference.isDisabledByAdmin() && !hasSecurity) {
+ trustAgentPreference.setEnabled(false);
+ trustAgentPreference.setSummary(R.string.disabled_because_no_backup_security);
+ }
+ // Add preference to the settings menu.
+ mSecurityCategory.addPreference(trustAgentPreference);
+ }
+ }
+
+ public void handleActivityResult(int resultCode) {
+ if (resultCode == Activity.RESULT_OK && mTrustAgentClickIntent != null) {
+ mHost.startActivity(mTrustAgentClickIntent);
+ mTrustAgentClickIntent = null;
+ }
+ }
+}
diff --git a/src/com/android/settings/utils/FileSizeFormatter.java b/src/com/android/settings/utils/FileSizeFormatter.java
index c0d360f..e56388a 100644
--- a/src/com/android/settings/utils/FileSizeFormatter.java
+++ b/src/com/android/settings/utils/FileSizeFormatter.java
@@ -16,22 +16,11 @@
package com.android.settings.utils;
-import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
-import android.icu.text.DecimalFormat;
-import android.icu.text.MeasureFormat;
-import android.icu.text.NumberFormat;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
import android.text.BidiFormatter;
-import android.text.TextUtils;
import android.text.format.Formatter;
-import android.view.View;
-
-import java.math.BigDecimal;
-import java.util.Locale;
/**
* Utility class to aid in formatting file sizes always with the same unit. This is modified from
@@ -42,61 +31,6 @@
public static final long MEGABYTE_IN_BYTES = KILOBYTE_IN_BYTES * 1000;
public static final long GIGABYTE_IN_BYTES = MEGABYTE_IN_BYTES * 1000;
- private static class RoundedBytesResult {
- public final float value;
- public final MeasureUnit units;
- public final int fractionDigits;
- public final long roundedBytes;
-
- public RoundedBytesResult(
- float value, MeasureUnit units, int fractionDigits, long roundedBytes) {
- this.value = value;
- this.units = units;
- this.fractionDigits = fractionDigits;
- this.roundedBytes = roundedBytes;
- }
- }
-
- private static Locale localeFromContext(@NonNull Context context) {
- return context.getResources().getConfiguration().locale;
- }
-
- private static String bidiWrap(@NonNull Context context, String source) {
- final Locale locale = localeFromContext(context);
- if (TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL) {
- return BidiFormatter.getInstance(true /* RTL*/).unicodeWrap(source);
- } else {
- return source;
- }
- }
-
- private static NumberFormat getNumberFormatter(Locale locale, int fractionDigits) {
- final NumberFormat numberFormatter = NumberFormat.getInstance(locale);
- numberFormatter.setMinimumFractionDigits(fractionDigits);
- numberFormatter.setMaximumFractionDigits(fractionDigits);
- numberFormatter.setGroupingUsed(false);
- if (numberFormatter instanceof DecimalFormat) {
- // We do this only for DecimalFormat, since in the general NumberFormat case, calling
- // setRoundingMode may throw an exception.
- numberFormatter.setRoundingMode(BigDecimal.ROUND_HALF_UP);
- }
- return numberFormatter;
- }
-
- private static String formatMeasureShort(Locale locale, NumberFormat numberFormatter,
- float value, MeasureUnit units) {
- final MeasureFormat measureFormatter = MeasureFormat.getInstance(
- locale, MeasureFormat.FormatWidth.SHORT, numberFormatter);
- return measureFormatter.format(new Measure(value, units));
- }
-
- private static String formatRoundedBytesResult(
- @NonNull Context context, @NonNull RoundedBytesResult input) {
- final Locale locale = localeFromContext(context);
- final NumberFormat numberFormatter = getNumberFormatter(locale, input.fractionDigits);
- return formatMeasureShort(locale, numberFormatter, input.value, input.units);
- }
-
/**
* Formats a content size to be in the form of bytes, kilobytes, megabytes, etc.
*
@@ -113,17 +47,23 @@
*
* @param context Context to use to load the localized units
* @param sizeBytes size value to be formatted, in bytes
- * @param unit The unit used for formatting.
- * @param mult Amount of bytes in the unit.
- * @return formatted string with the number
+ * @param suffix String id for the unit suffix.
+ * @param mult Amount of bytes in the unit. * @return formatted string with the number
*/
public static String formatFileSize(
- @Nullable Context context, long sizeBytes, MeasureUnit unit, long mult) {
+ @Nullable Context context, long sizeBytes, int suffix, long mult) {
if (context == null) {
return "";
}
- final RoundedBytesResult res = formatBytes(sizeBytes, unit, mult);
- return bidiWrap(context, formatRoundedBytesResult(context, res));
+ final Formatter.BytesResult res =
+ formatBytes(context.getResources(), sizeBytes, suffix, mult);
+ return BidiFormatter.getInstance()
+ .unicodeWrap(context.getString(getFileSizeSuffix(context), res.value, res.units));
+ }
+
+ private static int getFileSizeSuffix(Context context) {
+ final Resources res = context.getResources();
+ return res.getIdentifier("fileSizeSuffix", "string", "android");
}
/**
@@ -136,8 +76,8 @@
* @param suffix String id for the unit suffix.
* @param mult Amount of bytes in the unit.
*/
- private static RoundedBytesResult formatBytes(
- long sizeBytes, MeasureUnit unit, long mult) {
+ private static Formatter.BytesResult formatBytes(
+ Resources res, long sizeBytes, int suffix, long mult) {
final boolean isNegative = (sizeBytes < 0);
float result = isNegative ? -sizeBytes : sizeBytes;
result = result / mult;
@@ -145,29 +85,32 @@
// compute the rounded value. String.format("%f", 0.1) might not return "0.1" due to
// floating point errors.
final int roundFactor;
- final int roundDigits;
+ final String roundFormat;
if (mult == 1) {
roundFactor = 1;
- roundDigits = 0;
+ roundFormat = "%.0f";
} else if (result < 1) {
roundFactor = 100;
- roundDigits = 2;
+ roundFormat = "%.2f";
} else if (result < 10) {
roundFactor = 10;
- roundDigits = 1;
+ roundFormat = "%.1f";
} else { // 10 <= result < 100
roundFactor = 1;
- roundDigits = 0;
+ roundFormat = "%.0f";
}
if (isNegative) {
result = -result;
}
+ final String roundedString = String.format(roundFormat, result);
// Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
// it's okay (for now)...
final long roundedBytes = (((long) Math.round(result * roundFactor)) * mult / roundFactor);
- return new RoundedBytesResult(result, unit, roundDigits, roundedBytes);
+ final String units = res.getString(suffix);
+
+ return new Formatter.BytesResult(roundedString, units, roundedBytes);
}
}
diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
index c330340..6c663ab 100644
--- a/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFragmentTest.java
@@ -91,6 +91,19 @@
}
@Test
+ public void testPreferenceControllerSetter_shouldAddAndNotReplace() {
+ final TestPreferenceController controller1 = new TestPreferenceController(mContext);
+ mTestFragment.addPreferenceController(controller1);
+ final TestPreferenceController controller2 = new TestPreferenceController(mContext);
+ mTestFragment.addPreferenceController(controller2);
+
+ final TestPreferenceController retrievedController = mTestFragment.getPreferenceController
+ (TestPreferenceController.class);
+
+ assertThat(controller1).isSameAs(retrievedController);
+ }
+
+ @Test
public void displayTilesAsPreference_shouldAddTilesWithIntent() {
when(mFakeFeatureFactory.dashboardFeatureProvider
.getTilesForCategory(nullable(String.class)))
@@ -146,6 +159,23 @@
}
@Test
+ public void updateState_doesNotSkipControllersOfSameClass() {
+ final AbstractPreferenceController mockController1 =
+ mock(AbstractPreferenceController.class);
+ final AbstractPreferenceController mockController2 =
+ mock(AbstractPreferenceController.class);
+ mTestFragment.addPreferenceController(mockController1);
+ mTestFragment.addPreferenceController(mockController2);
+ when(mockController1.isAvailable()).thenReturn(true);
+ when(mockController2.isAvailable()).thenReturn(true);
+
+ mTestFragment.updatePreferenceStates();
+
+ verify(mockController1).getPreferenceKey();
+ verify(mockController2).getPreferenceKey();
+ }
+
+ @Test
public void tintTileIcon_hasMetadata_shouldReturnIconTintableMetadata() {
final Tile tile = new Tile();
tile.icon = mock(Icon.class);
diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
index b20823b..1a3139d 100644
--- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java
@@ -92,6 +92,8 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+ SettingsShadowResources.overrideResource("android:string/fileSizeSuffix", "%1$s %2$s");
+ SettingsShadowResources.overrideResource("android:string/gigabyteShort", "GB");
when(mFragment.getActivity()).thenReturn(mActivity);
when(mFragment.getFragmentManager()).thenReturn(mFragmentManager);
when(mFragmentManager.beginTransaction()).thenReturn(mFragmentTransaction);
diff --git a/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java b/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java
index 4213fc5..374b7ec 100644
--- a/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/security/screenlock/ScreenLockSettingsTest.java
@@ -33,6 +33,8 @@
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
@RunWith(SettingsRobolectricTestRunner.class)
@@ -55,10 +57,12 @@
@Test
public void onOwnerInfoUpdated_shouldUpdateOwnerInfoController() {
- final Map<Class, AbstractPreferenceController> preferenceControllers =
+ final Map<Class, List<AbstractPreferenceController>> preferenceControllers =
ReflectionHelpers.getField(mSettings, "mPreferenceControllers");
final OwnerInfoPreferenceController controller = mock(OwnerInfoPreferenceController.class);
- preferenceControllers.put(OwnerInfoPreferenceController.class, controller);
+ List<AbstractPreferenceController> controllerList = new ArrayList<>();
+ controllerList.add(controller);
+ preferenceControllers.put(OwnerInfoPreferenceController.class, controllerList);
mSettings.onOwnerInfoUpdated();
diff --git a/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java
new file mode 100644
index 0000000..a97780b
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/security/trustagent/TrustAgentListPreferenceControllerTest.java
@@ -0,0 +1,132 @@
+/*
+ * 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.security.trustagent;
+
+
+import static com.android.settings.security.trustagent.TrustAgentListPreferenceController
+ .PREF_KEY_SECURITY_CATEGORY;
+import static com.android.settings.security.trustagent.TrustAgentListPreferenceController
+ .PREF_KEY_TRUST_AGENT;
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceCategory;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.settings.TestConfig;
+import com.android.settings.security.SecuritySettingsV2;
+import com.android.settings.testutils.FakeFeatureFactory;
+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.Robolectric;
+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)
+public class TrustAgentListPreferenceControllerTest {
+
+ @Mock
+ private TrustAgentManager mTrustAgentManager;
+ @Mock
+ private LockPatternUtils mLockPatternUtils;
+ @Mock
+ private PreferenceScreen mScreen;
+ @Mock
+ private PreferenceCategory mCategory;
+ @Mock
+ private SecuritySettingsV2 mFragment;
+
+ private Lifecycle mLifecycle;
+ private FakeFeatureFactory mFeatureFactory;
+ private Activity mActivity;
+
+ private TrustAgentListPreferenceController mController;
+
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mActivity = Robolectric.buildActivity(Activity.class).get();
+ mLifecycle = new Lifecycle(() -> mLifecycle);
+ mFeatureFactory = FakeFeatureFactory.setupForTest();
+ when(mFeatureFactory.securityFeatureProvider.getLockPatternUtils(any(Context.class)))
+ .thenReturn(mLockPatternUtils);
+ when(mFeatureFactory.securityFeatureProvider.getTrustAgentManager())
+ .thenReturn(mTrustAgentManager);
+ when(mCategory.getKey()).thenReturn(PREF_KEY_SECURITY_CATEGORY);
+ when(mCategory.getContext()).thenReturn(mActivity);
+ when(mScreen.findPreference(PREF_KEY_SECURITY_CATEGORY))
+ .thenReturn(mCategory);
+ mController = new TrustAgentListPreferenceController(mActivity, mFragment, mLifecycle);
+ }
+
+ @Test
+ public void testConstants() {
+ assertThat(mController.isAvailable()).isTrue();
+ assertThat(mController.getPreferenceKey()).isEqualTo(PREF_KEY_TRUST_AGENT);
+ }
+
+ @Test
+ public void onResume_shouldClearOldAgents() {
+ final Preference oldAgent = new Preference(mActivity);
+ oldAgent.setKey(PREF_KEY_TRUST_AGENT);
+ when(mCategory.findPreference(PREF_KEY_TRUST_AGENT))
+ .thenReturn(oldAgent)
+ .thenReturn(null);
+
+ mController.displayPreference(mScreen);
+ mController.onResume();
+
+ verify(mCategory).removePreference(oldAgent);
+ }
+
+ @Test
+ public void onResume_shouldAddNewAgents() {
+ final List<TrustAgentManager.TrustAgentComponentInfo> agents = new ArrayList<>();
+ final TrustAgentManager.TrustAgentComponentInfo agent = mock(
+ TrustAgentManager.TrustAgentComponentInfo.class);
+ agent.title = "Test_title";
+ agent.summary = "test summary";
+ agent.componentName = new ComponentName("pkg", "agent");
+ agent.admin = null;
+ agents.add(agent);
+ when(mTrustAgentManager.getActiveTrustAgents(mActivity, mLockPatternUtils))
+ .thenReturn(agents);
+
+ mController.displayPreference(mScreen);
+ mController.onResume();
+
+ verify(mCategory).addPreference(any(Preference.class));
+ }
+}
diff --git a/tests/unit/README b/tests/unit/README
index 2544ea5..5184b07 100644
--- a/tests/unit/README
+++ b/tests/unit/README
@@ -1,8 +1,8 @@
To build the tests you can use the following command at the root of your android source tree
-$ make -j SettingsUnitTests
+$ make SettingsUnitTests
The test apk then needs to be installed onto your test device via for example
-$ adb install -r ${ANDROID_PRODUCT_OUT}/data/app/SettingsUnitTests/SettingsUnitTests.apk
+$ adb install -r out/target/product/shamu/data/app/SettingsUnitTests/SettingsUnitTests.apk
To run all tests:
$ adb shell am instrument -w com.android.settings.tests.unit/android.support.test.runner.AndroidJUnitRunner
diff --git a/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java b/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java
index 41b236c..c5b050a 100644
--- a/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java
+++ b/tests/unit/src/com/android/settings/utils/FileSizeFormatterTest.java
@@ -22,7 +22,6 @@
import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
-import android.icu.util.MeasureUnit;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -47,7 +46,7 @@
FileSizeFormatter.formatFileSize(
mContext,
0 /* size */,
- MeasureUnit.GIGABYTE,
+ com.android.internal.R.string.gigabyteShort,
GIGABYTE_IN_BYTES))
.isEqualTo("0.00 GB");
}
@@ -58,7 +57,7 @@
FileSizeFormatter.formatFileSize(
mContext,
MEGABYTE_IN_BYTES * 11 /* size */,
- MeasureUnit.GIGABYTE,
+ com.android.internal.R.string.gigabyteShort,
GIGABYTE_IN_BYTES))
.isEqualTo("0.01 GB");
}
@@ -69,7 +68,7 @@
FileSizeFormatter.formatFileSize(
mContext,
MEGABYTE_IN_BYTES * 155 /* size */,
- MeasureUnit.GIGABYTE,
+ com.android.internal.R.string.gigabyteShort,
GIGABYTE_IN_BYTES))
.isEqualTo("0.16 GB");
}
@@ -80,7 +79,7 @@
FileSizeFormatter.formatFileSize(
mContext,
MEGABYTE_IN_BYTES * 1551 /* size */,
- MeasureUnit.GIGABYTE,
+ com.android.internal.R.string.gigabyteShort,
GIGABYTE_IN_BYTES))
.isEqualTo("1.6 GB");
}
@@ -92,7 +91,7 @@
FileSizeFormatter.formatFileSize(
mContext,
GIGABYTE_IN_BYTES * 15 + MEGABYTE_IN_BYTES * 50 /* size */,
- MeasureUnit.GIGABYTE,
+ com.android.internal.R.string.gigabyteShort,
GIGABYTE_IN_BYTES))
.isEqualTo("15 GB");
}
@@ -103,7 +102,7 @@
FileSizeFormatter.formatFileSize(
mContext,
MEGABYTE_IN_BYTES * -155 /* size */,
- MeasureUnit.GIGABYTE,
+ com.android.internal.R.string.gigabyteShort,
GIGABYTE_IN_BYTES))
.isEqualTo("-0.16 GB");
}