android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
- android:layout_marginBottom="16dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingTop="16dp"
+ android:paddingBottom="16dp"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<LinearLayout
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dip"
+ android:minWidth="32dp"
android:text="@string/progress_scanning"/>
</LinearLayout>
<!-- Title for the installed app info storage page. The total storage space taken up by this app. [CHAR LIMIT=40]-->
<string name="app_info_storage_title">Space used</string>
+ <!-- The divider symbol between different parts of the notification header including spaces. not translatable [CHAR LIMIT=3] -->
+ <string name="notification_header_divider_symbol_with_spaces" translatable="false">" • "</string>
+
+
</resources>
android:selectable="false"/>
</PreferenceCategory>
- <PreferenceCategory android:title="@string/enterprise_privacy_exposure_changes_category">
+ <PreferenceCategory android:title="@string/enterprise_privacy_exposure_changes_category"
+ android:key="exposure_changes_category">
<Preference android:fragment="com.android.settings.enterprise.ApplicationListFragment$EnterpriseInstalledPackages"
android:key="number_enterprise_installed_packages"
android:title="@string/enterprise_privacy_enterprise_installed_packages"/>
<!-- IPv6 Details -->
<PreferenceCategory
- android:key="ipv6_details_category"
+ android:key="ipv6_category"
android:title="@string/wifi_details_ipv6_address_header"
- android:selectable="false"/>
+ android:selectable="false">
+ <Preference
+ android:key="ipv6_addresses"
+ android:selectable="false"/>
+ </PreferenceCategory>
</PreferenceScreen>
}
/**
- * Returns the managed profile of the current user or null if none found.
+ * Returns the managed profile of the current user or {@code null} if none is found or a profile
+ * exists but it is disabled.
*/
public static UserHandle getManagedProfile(UserManager userManager) {
List<UserHandle> userProfiles = userManager.getUserProfiles();
}
/**
+ * Returns the managed profile of the current user or {@code null} if none is found. Unlike
+ * {@link #getManagedProfile} this method returns enabled and disabled managed profiles.
+ */
+ public static UserHandle getManagedProfileWithDisabled(UserManager userManager) {
+ // TODO: Call getManagedProfileId from here once Robolectric supports
+ // API level 24 and UserManager.getProfileIdsWithDisabled can be Mocked (to avoid having
+ // yet another implementation that loops over user profiles in this method). In the meantime
+ // we need to use UserManager.getProfiles that is available on API 23 (the one currently
+ // used for Settings Robolectric tests).
+ final int myUserId = UserHandle.myUserId();
+ List<UserInfo> profiles = userManager.getProfiles(myUserId);
+ final int count = profiles.size();
+ for (int i = 0; i < count; i++) {
+ final UserInfo profile = profiles.get(i);
+ if (profile.isManagedProfile()
+ && profile.getUserHandle().getIdentifier() != myUserId) {
+ return profile.getUserHandle();
+ }
+ }
+ return null;
+ }
+
+ /**
* Retrieves the id for the given user's managed profile.
*
* @return the managed profile id or UserHandle.USER_NULL if there is none.
public AutoSyncWorkDataPreferenceController(Context context, Fragment parent) {
super(context, parent);
- mUserHandle = Utils.getManagedProfile(mUserManager);
+ mUserHandle = Utils.getManagedProfileWithDisabled(mUserManager);
}
@Override
private Preference mPreference;
private PreferenceScreen mScreen;
+ private PreferenceAvailabilityObserver mAvailabilityObserver = null;
public DynamicAvailabilityPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
}
}
+ public void setAvailabilityObserver(PreferenceAvailabilityObserver observer) {
+ mAvailabilityObserver = observer;
+ }
+
+ public PreferenceAvailabilityObserver getAvailabilityObserver() {
+ return mAvailabilityObserver;
+ }
+
@Override
public void displayPreference(PreferenceScreen screen) {
mScreen = screen;
mScreen.addPreference(mPreference);
}
}
+
+ protected void notifyOnAvailabilityUpdate(boolean available) {
+ if (mAvailabilityObserver != null) {
+ mAvailabilityObserver.onPreferenceAvailabilityUpdated(getPreferenceKey(), available);
+ }
+ }
}
--- /dev/null
+/*
+ * 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.core;
+
+/**
+ * @deprecated This interface allows a {@link android.support.v7.preference.PreferenceGroup}'s
+ * controller to observe the availability of the {@link android.support.v7.preference.Preference}s
+ * inside it, hiding the group when all preferences become unavailable. In the future,
+ * {@link android.support.v7.preference.PreferenceGroup} will have native support for that
+ * functionality, removing the need for this interface.
+ */
+public interface PreferenceAvailabilityObserver {
+
+ /**
+ * Notifies the observer that the availability of the preference identified by {@code key} has
+ * been updated.
+ */
+ void onPreferenceAvailabilityUpdated(String key, boolean available);
+}
true /* async */,
(num) -> {
if (num == 0) {
- preference.setVisible(false);
mHasApps = false;
} else {
- preference.setVisible(true);
preference.setSummary(mContext.getResources().getQuantityString(
R.plurals.enterprise_privacy_number_packages_lower_bound,
num, num));
mHasApps = true;
}
+ preference.setVisible(mHasApps);
+ notifyOnAvailabilityUpdate(mHasApps);
});
}
mFeatureProvider.calculateNumberOfAppsWithAdminGrantedPermissions(mPermissions,
false /* async */, (num) -> haveAppsWithAdminGrantedPermissions[0] = num > 0);
mHasApps = haveAppsWithAdminGrantedPermissions[0];
+ notifyOnAvailabilityUpdate(mHasApps);
return mHasApps;
}
@Override
public boolean isAvailable() {
- return mFeatureProvider.isAlwaysOnVpnSetInCurrentUser();
+ final boolean available = mFeatureProvider.isAlwaysOnVpnSetInCurrentUser();
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
@Override
public boolean isAvailable() {
- return mFeatureProvider.isAlwaysOnVpnSetInManagedProfile();
+ final boolean available = mFeatureProvider.isAlwaysOnVpnSetInManagedProfile();
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
@Override
public boolean isAvailable() {
- return mFeatureProvider.getNumberOfOwnerInstalledCaCertsForCurrentUserAndManagedProfile()
- > 0;
+ final boolean available =
+ mFeatureProvider.getNumberOfOwnerInstalledCaCertsForCurrentUserAndManagedProfile()
+ > 0;
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
public void updateState(Preference preference) {
mFeatureProvider.calculateNumberOfPolicyInstalledApps(true /* async */,
(num) -> {
+ final boolean available;
if (num == 0) {
- preference.setVisible(false);
+ available = false;
} else {
- preference.setVisible(true);
+ available = true;
preference.setSummary(mContext.getResources().getQuantityString(
R.plurals.enterprise_privacy_number_packages_lower_bound, num,
num));
+
}
+ preference.setVisible(available);
+ notifyOnAvailabilityUpdate(available);
});
}
final Boolean[] haveEnterpriseInstalledPackages = { null };
mFeatureProvider.calculateNumberOfPolicyInstalledApps(false /* async */,
(num) -> haveEnterpriseInstalledPackages[0] = num > 0);
- return haveEnterpriseInstalledPackages[0];
+ final boolean available = haveEnterpriseInstalledPackages[0];
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
@Override
public boolean isAvailable() {
- return mFeatureProvider.hasDeviceOwner();
+ final boolean available = mFeatureProvider.hasDeviceOwner();
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
controllers.add(new NetworkLogsPreferenceController(context));
controllers.add(new BugReportsPreferenceController(context));
controllers.add(new SecurityLogsPreferenceController(context));
- controllers.add(new EnterpriseInstalledPackagesPreferenceController(context, lifecycle,
- async));
- controllers.add(new AdminGrantedLocationPermissionsPreferenceController(context, lifecycle,
- async));
- controllers.add(new AdminGrantedMicrophonePermissionPreferenceController(context, lifecycle,
- async));
- controllers.add(new AdminGrantedCameraPermissionPreferenceController(context, lifecycle,
- async));
- controllers.add(new EnterpriseSetDefaultAppsPreferenceController(context, lifecycle));
- controllers.add(new AlwaysOnVpnCurrentUserPreferenceController(context, lifecycle));
- controllers.add(new AlwaysOnVpnManagedProfilePreferenceController(context, lifecycle));
- controllers.add(new GlobalHttpProxyPreferenceController(context, lifecycle));
- controllers.add(new CaCertsPreferenceController(context, lifecycle));
+ final List exposureChangesCategoryControllers = new ArrayList<PreferenceController>();
+ exposureChangesCategoryControllers.add(new EnterpriseInstalledPackagesPreferenceController(
+ context, lifecycle, async));
+ exposureChangesCategoryControllers.add(
+ new AdminGrantedLocationPermissionsPreferenceController(context, lifecycle, async));
+ exposureChangesCategoryControllers.add(
+ new AdminGrantedMicrophonePermissionPreferenceController(context, lifecycle,
+ async));
+ exposureChangesCategoryControllers.add(new AdminGrantedCameraPermissionPreferenceController(
+ context, lifecycle, async));
+ exposureChangesCategoryControllers.add(new EnterpriseSetDefaultAppsPreferenceController(
+ context, lifecycle));
+ exposureChangesCategoryControllers.add(new AlwaysOnVpnCurrentUserPreferenceController(
+ context, lifecycle));
+ exposureChangesCategoryControllers.add(new AlwaysOnVpnManagedProfilePreferenceController(
+ context, lifecycle));
+ exposureChangesCategoryControllers.add(new ImePreferenceController(context, lifecycle));
+ exposureChangesCategoryControllers.add(new GlobalHttpProxyPreferenceController(context,
+ lifecycle));
+ exposureChangesCategoryControllers.add(new CaCertsPreferenceController(context, lifecycle));
+ controllers.addAll(exposureChangesCategoryControllers);
+ controllers.add(new ExposureChangesCategoryPreferenceController(context, lifecycle,
+ exposureChangesCategoryControllers, async));
controllers.add(new FailedPasswordWipeCurrentUserPreferenceController(context, lifecycle));
controllers.add(new FailedPasswordWipeManagedProfilePreferenceController(context,
lifecycle));
- controllers.add(new ImePreferenceController(context, lifecycle));
return controllers;
}
+
/*
* Copyright (C) 2017 The Android Open Source Project
*
@Override
public boolean isAvailable() {
- return getNumberOfEnterpriseSetDefaultApps() > 0;
+ final boolean available = getNumberOfEnterpriseSetDefaultApps() > 0;
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
--- /dev/null
+
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.core.DynamicAvailabilityPreferenceController;
+import com.android.settings.core.PreferenceAvailabilityObserver;
+import com.android.settings.core.lifecycle.Lifecycle;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * A controller that hides a {@link android.support.v7.preference.PreferenceGroup} when none of the
+ * {@link Preference}s inside it are visible.
+ *
+ * TODO(b/62051162): Use {@link android.support.v7.preference.PreferenceGroup}'s native ability to
+ * hide itself when all {@link Preference}s inside it are invisible when that functionality becomes
+ * available. This custom controller will still be needed to remove the
+ * {@link android.support.v7.preference.PreferenceGroup} from the search index as required (by
+ * having {@link #isAvailable()} return {@code false} if the method returns {@code false} for all
+ * {@link Preference}s in the {@link android.support.v7.preference.PreferenceGroup}).
+ */
+public class ExposureChangesCategoryPreferenceController
+ extends DynamicAvailabilityPreferenceController implements PreferenceAvailabilityObserver {
+
+ private static final String KEY_EXPOSURE_CHANGES_CATEGORY = "exposure_changes_category";
+ private final Set<String> mAvailablePrefs = new HashSet<String>();
+ private Preference mPreference = null;
+ private boolean mControllingUi;
+
+ /**
+ * When {@code controllingUi} is {@code true}, some of the preferences may have their visibility
+ * determined asynchronously. In this case, {@link #isAvailable()} must always return {@code
+ * true} and the group should be hidden using {@link Preference#setVisible()} if all preferences
+ * report that they are invisible.
+ * When {@code controllingUi} is {@code false}, we are running on the search indexer thread and
+ * visibility must be determined synchronously. {@link #isAvailable()} can rely on all
+ * preferences having their visibility determined already and should return whether the group is
+ * visible or not.
+ */
+ public ExposureChangesCategoryPreferenceController(Context context, Lifecycle lifecycle,
+ List<DynamicAvailabilityPreferenceController> controllers, boolean controllingUi) {
+ super(context, lifecycle);
+ mControllingUi = controllingUi;
+ for (final DynamicAvailabilityPreferenceController controller : controllers) {
+ controller.setAvailabilityObserver(this);
+ }
+ }
+
+ @Override
+ public void onPreferenceAvailabilityUpdated(String key, boolean available) {
+ if (available) {
+ mAvailablePrefs.add(key);
+ } else {
+ mAvailablePrefs.remove(key);
+ }
+ available = haveAnyVisiblePreferences();
+ if (mControllingUi) {
+ notifyOnAvailabilityUpdate(available);
+ }
+ if (mPreference != null) {
+ mPreference.setVisible(available);
+ }
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ mPreference = preference;
+ mPreference.setVisible(haveAnyVisiblePreferences());
+ }
+
+ @Override
+ public boolean isAvailable() {
+ if (mControllingUi) {
+ // When running on the main UI thread, some preferences determine their visibility
+ // asynchronously. Always return true here and determine the pref group's actual
+ // visibility as the other preferences report their visibility asynchronously via
+ // onPreferenceAvailabilityUpdated().
+ return true;
+ }
+ final boolean available = haveAnyVisiblePreferences();
+ notifyOnAvailabilityUpdate(available);
+ return available;
+ }
+
+ @Override
+ public String getPreferenceKey() {
+ return KEY_EXPOSURE_CHANGES_CATEGORY;
+ }
+
+ private boolean haveAnyVisiblePreferences() {
+ return mAvailablePrefs.size() > 0;
+ }
+}
@Override
public boolean isAvailable() {
- return getMaximumFailedPasswordsBeforeWipe() > 0;
+ final boolean available = getMaximumFailedPasswordsBeforeWipe() > 0;
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
}
@Override
public boolean isAvailable() {
- return mFeatureProvider.isGlobalHttpProxySet();
+ final boolean available = mFeatureProvider.isGlobalHttpProxySet();
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
@Override
public boolean isAvailable() {
- return mFeatureProvider.getImeLabelIfOwnerSet() != null;
+ final boolean available = mFeatureProvider.getImeLabelIfOwnerSet() != null;
+ notifyOnAvailabilityUpdate(available);
+ return available;
}
@Override
getPreferenceScreen().setOrderingAsAdded(true);
setupBlock();
addHeaderPref();
- addAppLinkPref();
mShowLegacyChannelConfig = mBackend.onlyHasDefaultChannel(mAppRow.pkg, mAppRow.uid);
if (mShowLegacyChannelConfig) {
return;
}
populateChannelList();
+ addAppLinkPref();
}
}.execute();
}
import android.app.Activity;
import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.content.Intent;
-import android.content.pm.UserInfo;
import android.net.Uri;
import android.os.Bundle;
-import android.os.UserHandle;
+import android.os.AsyncTask;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
+import android.text.BidiFormatter;
+import android.text.SpannableStringBuilder;
import android.util.ArrayMap;
import android.util.Log;
import android.view.LayoutInflater;
import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.internal.widget.LockPatternUtils;
import com.android.settings.AppHeader;
import com.android.settings.R;
import com.android.settings.RingtonePreference;
private RestrictedSwitchPreference mVibrate;
private NotificationSoundPreference mRingtone;
private FooterPreference mFooter;
+ private NotificationChannelGroup mChannelGroup;
+ private AppHeaderController mHeaderPref;
@Override
public int getMetricsCategory() {
mShowLegacyChannelConfig = true;
} else {
populateUpgradedChannelPrefs();
+
+ if (mChannel.getGroup() != null) {
+ // Go look up group name
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... unused) {
+ if (mChannel.getGroup() != null) {
+ mChannelGroup = mBackend.getGroup(mChannel.getGroup(), mPkg, mUid);
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void unused) {
+ if (getHost() == null || mChannelGroup == null) {
+ return;
+ }
+ setChannelGroupLabel(mChannelGroup.getName());
+ }
+ }.execute();
+ }
}
updateDependents(mChannel.getImportance() == IMPORTANCE_NONE);
rows.put(mAppRow.pkg, mAppRow);
collectConfigActivities(rows);
final Activity activity = getActivity();
- final Preference pref = FeatureFactory.getFactory(activity)
+ mHeaderPref = FeatureFactory.getFactory(activity)
.getApplicationFeatureProvider(activity)
- .newAppHeaderController(this /* fragment */, null /* appHeader */)
+ .newAppHeaderController(this /* fragment */, null /* appHeader */);
+ final Preference pref = mHeaderPref
.setIcon(mAppRow.icon)
.setLabel(mChannel.getName())
.setSummary(mAppRow.label)
getPreferenceScreen().addPreference(pref);
}
+ private void setChannelGroupLabel(CharSequence groupName) {
+ final SpannableStringBuilder summary = new SpannableStringBuilder();
+ BidiFormatter bidi = BidiFormatter.getInstance();
+ summary.append(bidi.unicodeWrap(mAppRow.label.toString()));
+ if (groupName != null) {
+ summary.append(bidi.unicodeWrap(mContext.getText(
+ R.string.notification_header_divider_symbol_with_spaces)));
+ summary.append(bidi.unicodeWrap(groupName.toString()));
+ }
+ final Activity activity = getActivity();
+ mHeaderPref.setSummary(summary.toString());
+ mHeaderPref.done(activity, getPrefContext());
+ }
+
private void addFooterPref() {
if (!TextUtils.isEmpty(mChannel.getDescription())) {
FooterPreference descPref = new FooterPreference(getPrefContext());
private void setupVibrate() {
mVibrate = (RestrictedSwitchPreference) findPreference(KEY_VIBRATE);
mVibrate.setDisabledByAdmin(mSuspendedAppsAdmin);
+ mVibrate.setEnabled(!(mAppRow.lockedImportance || mVibrate.isDisabledByAdmin()));
mVibrate.setChecked(mChannel.shouldVibrate());
mVibrate.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
private void setupRingtone() {
mRingtone = (NotificationSoundPreference) findPreference(KEY_RINGTONE);
mRingtone.setRingtone(mChannel.getSound());
+ mRingtone.setEnabled(!(mAppRow.lockedImportance));
mRingtone.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
channelArgs.putBoolean(AppHeader.EXTRA_HIDE_INFO_BUTTON, true);
channelArgs.putString(AppInfoBase.ARG_PACKAGE_NAME, mPkg);
channelArgs.putString(Settings.EXTRA_CHANNEL_ID, mChannel.getId());
- Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
- ChannelImportanceSettings.class.getName(),
- channelArgs, null, R.string.notification_importance_title, null,
- false, getMetricsCategory());
- mImportance.setIntent(channelIntent);
- mImportance.setEnabled(mSuspendedAppsAdmin == null);
+ mImportance.setEnabled(mSuspendedAppsAdmin == null && !mAppRow.lockedImportance);
+ // Set up intent to show importance selection only if this setting is enabled.
+ if (mImportance.isEnabled()) {
+ Intent channelIntent = Utils.onBuildStartFragmentIntent(getActivity(),
+ ChannelImportanceSettings.class.getName(),
+ channelArgs, null, R.string.notification_importance_title, null,
+ false, getMetricsCategory());
+ mImportance.setIntent(channelIntent);
+ }
mImportance.setSummary(getImportanceSummary(mChannel.getImportance()));
}
if (mAppLink != null) {
setVisible(mAppLink, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
}
- if (mFooter !=null) {
+ if (mFooter != null) {
setVisible(mFooter, checkCanBeVisible(NotificationManager.IMPORTANCE_MIN));
}
}
}
}
+
+ public NotificationChannelGroup getGroup(String groupId, String pkg, int uid) {
+ if (groupId == null) {
+ return null;
+ }
+ try {
+ return sINM.getNotificationChannelGroupForPackage(groupId, pkg, uid);
+ } catch (Exception e) {
+ Log.w(TAG, "Error calling NoMan", e);
+ return null;
+ }
+ }
+
public ParceledListSlice<NotificationChannelGroup> getChannelGroups(String pkg, int uid) {
try {
return sINM.getNotificationChannelGroupsForPackage(pkg, uid, false);
}
protected void addAppLinkPref() {
- if (mAppRow.settingsIntent != null) {
+ if (mAppRow.settingsIntent != null && mAppLink == null) {
mAppLink = new Preference(getPrefContext());
mAppLink.setKey(KEY_APP_LINK);
mAppLink.setOrder(500);
private void setupImportanceToggle() {
mImportanceToggle = (RestrictedSwitchPreference) findPreference(KEY_ALLOW_SOUND);
mImportanceToggle.setDisabledByAdmin(mSuspendedAppsAdmin);
+ mImportanceToggle.setEnabled(!(mAppRow.lockedImportance
+ || mImportanceToggle.isDisabledByAdmin()));
mImportanceToggle.setChecked(mChannel.getImportance() >= IMPORTANCE_DEFAULT
|| mChannel.getImportance() == IMPORTANCE_UNSPECIFIED);
mImportanceToggle.setOnPreferenceChangeListener(
protected void setupPriorityPref(boolean priority) {
mPriority = (RestrictedSwitchPreference) findPreference(KEY_BYPASS_DND);
mPriority.setDisabledByAdmin(mSuspendedAppsAdmin);
+ mPriority.setEnabled(!(mAppRow.lockedImportance || mPriority.isDisabledByAdmin()));
mPriority.setChecked(priority);
mPriority.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
mStopped = true;
if (mVolumizer != null) {
mVolumizer.stop();
+ mVolumizer = null;
}
}
-
+
@Override
public void onBindViewHolder(PreferenceViewHolder view) {
super.onBindViewHolder(view);
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
}
public void setDetailText(String text) {
+ if (TextUtils.equals(mDetailText, text)) return;
mDetailText = text;
notifyChanged();
}
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IpPrefix;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkBadging;
import java.net.UnknownHostException;
import java.util.List;
import java.util.StringJoiner;
+import java.util.stream.Collectors;
/**
* Controller for logic pertaining to displaying Wifi information for the
@VisibleForTesting
static final String KEY_DNS_PREF = "dns";
@VisibleForTesting
- static final String KEY_IPV6_ADDRESS_CATEGORY = "ipv6_details_category";
+ static final String KEY_IPV6_CATEGORY = "ipv6_category";
+ @VisibleForTesting
+ static final String KEY_IPV6_ADDRESSES_PREF = "ipv6_addresses";
private AccessPoint mAccessPoint;
private final ConnectivityManagerWrapper mConnectivityManagerWrapper;
private WifiDetailPreference mGatewayPref;
private WifiDetailPreference mSubnetPref;
private WifiDetailPreference mDnsPref;
+ private PreferenceCategory mIpv6Category;
+ private Preference mIpv6AddressPref;
- private PreferenceCategory mIpv6AddressCategory;
private final IntentFilter mFilter;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
mSubnetPref = (WifiDetailPreference) screen.findPreference(KEY_SUBNET_MASK_PREF);
mDnsPref = (WifiDetailPreference) screen.findPreference(KEY_DNS_PREF);
- mIpv6AddressCategory =
- (PreferenceCategory) screen.findPreference(KEY_IPV6_ADDRESS_CATEGORY);
+ mIpv6Category = (PreferenceCategory) screen.findPreference(KEY_IPV6_CATEGORY);
+ mIpv6AddressPref = (Preference) screen.findPreference(KEY_IPV6_ADDRESSES_PREF);
mSecurityPref.setDetailText(mAccessPoint.getSecurityString(false /* concise */));
mForgetButton = (Button) mButtonsPref.findViewById(R.id.forget_button);
mFrequencyPref.setDetailText(band);
updateIpLayerInfo();
- mButtonsPref.setVisible(mForgetButton.getVisibility() == View.VISIBLE
- || mSignInButton.getVisibility() == View.VISIBLE);
}
private void exitActivity() {
mSignalStrengthPref.setDetailText(mSignalStr[summarySignalLevel]);
}
+ private void updatePreference(WifiDetailPreference pref, String detailText) {
+ if (!TextUtils.isEmpty(detailText)) {
+ pref.setDetailText(detailText);
+ pref.setVisible(true);
+ } else {
+ pref.setVisible(false);
+ }
+ }
+
private void updateIpLayerInfo() {
mSignInButton.setVisibility(canSignIntoNetwork() ? View.VISIBLE : View.INVISIBLE);
-
- // Reset all fields
- mIpv6AddressCategory.removeAll();
- mIpv6AddressCategory.setVisible(false);
- mIpAddressPref.setVisible(false);
- mSubnetPref.setVisible(false);
- mGatewayPref.setVisible(false);
- mDnsPref.setVisible(false);
+ mButtonsPref.setVisible(mForgetButton.getVisibility() == View.VISIBLE
+ || mSignInButton.getVisibility() == View.VISIBLE);
if (mNetwork == null || mLinkProperties == null) {
+ mIpAddressPref.setVisible(false);
+ mSubnetPref.setVisible(false);
+ mGatewayPref.setVisible(false);
+ mDnsPref.setVisible(false);
+ mIpv6Category.setVisible(false);
return;
}
- List<InetAddress> addresses = mLinkProperties.getAddresses();
-
- // Set IPv4 and IPv6 addresses
- for (int i = 0; i < addresses.size(); i++) {
- InetAddress addr = addresses.get(i);
- if (addr instanceof Inet4Address) {
- mIpAddressPref.setDetailText(addr.getHostAddress());
- mIpAddressPref.setVisible(true);
- } else if (addr instanceof Inet6Address) {
- String ip = addr.getHostAddress();
- Preference pref = new Preference(mPrefContext);
- pref.setKey(ip);
- pref.setTitle(ip);
- pref.setSelectable(false);
- mIpv6AddressCategory.addPreference(pref);
- mIpv6AddressCategory.setVisible(true);
+
+ // Find IPv4 and IPv6 addresses.
+ String ipv4Address = null;
+ String subnet = null;
+ StringJoiner ipv6Addresses = new StringJoiner("\n");
+
+ for (LinkAddress addr : mLinkProperties.getLinkAddresses()) {
+ if (addr.getAddress() instanceof Inet4Address) {
+ ipv4Address = addr.getAddress().getHostAddress();
+ subnet = ipv4PrefixLengthToSubnetMask(addr.getPrefixLength());
+ } else if (addr.getAddress() instanceof Inet6Address) {
+ ipv6Addresses.add(addr.getAddress().getHostAddress());
}
}
- // Set up IPv4 gateway and subnet mask
+ // Find IPv4 default gateway.
String gateway = null;
- String subnet = null;
for (RouteInfo routeInfo : mLinkProperties.getRoutes()) {
- if (routeInfo.hasGateway() && routeInfo.getGateway() instanceof Inet4Address) {
+ if (routeInfo.isIPv4Default() && routeInfo.hasGateway()) {
gateway = routeInfo.getGateway().getHostAddress();
+ break;
}
- IpPrefix ipPrefix = routeInfo.getDestination();
- if (ipPrefix != null && ipPrefix.getAddress() instanceof Inet4Address
- && ipPrefix.getPrefixLength() > 0) {
- subnet = ipv4PrefixLengthToSubnetMask(ipPrefix.getPrefixLength());
- }
- }
-
- if (!TextUtils.isEmpty(subnet)) {
- mSubnetPref.setDetailText(subnet);
- mSubnetPref.setVisible(true);
}
- if (!TextUtils.isEmpty(gateway)) {
- mGatewayPref.setDetailText(gateway);
- mGatewayPref.setVisible(true);
- }
-
- // Set IPv4 DNS addresses
- StringJoiner stringJoiner = new StringJoiner(",");
- for (InetAddress dnsServer : mLinkProperties.getDnsServers()) {
- if (dnsServer instanceof Inet4Address) {
- stringJoiner.add(dnsServer.getHostAddress());
- }
- }
- String dnsText = stringJoiner.toString();
- if (!dnsText.isEmpty()) {
- mDnsPref.setDetailText(dnsText);
- mDnsPref.setVisible(true);
+ // Find IPv4 DNS addresses.
+ String dnsServers = mLinkProperties.getDnsServers().stream()
+ .filter(Inet4Address.class::isInstance)
+ .map(InetAddress::getHostAddress)
+ .collect(Collectors.joining(","));
+
+ // Update UI.
+ updatePreference(mIpAddressPref, ipv4Address);
+ updatePreference(mSubnetPref, subnet);
+ updatePreference(mGatewayPref, gateway);
+ updatePreference(mDnsPref, dnsServers);
+
+ if (ipv6Addresses.length() > 0) {
+ mIpv6AddressPref.setSummary(ipv6Addresses.toString());
+ mIpv6Category.setVisible(true);
+ } else {
+ mIpv6Category.setVisible(false);
}
}
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.when;
import android.app.Fragment;
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AutoSyncWorkDataPreferenceControllerTest {
+ private static int MANAGED_PROFILE_ID = 10;
+
@Mock(answer = RETURNS_DEEP_STUBS)
private UserManager mUserManager;
@Mock(answer = RETURNS_DEEP_STUBS)
@Test
public void checkIsAvailable_singleUserProfile_shouldNotDisplay() {
- final List<UserInfo> infos = new ArrayList<>();
- infos.add(new UserInfo(1, "user 1", 0));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false);
- when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
+
+ final List<UserInfo> infos = new ArrayList<>();
+ infos.add(new UserInfo(UserHandle.USER_SYSTEM, "user 1", 0 /* flags */));
+ when(mUserManager.getProfiles(eq(UserHandle.USER_SYSTEM))).thenReturn(infos);
assertThat(mController.isAvailable()).isFalse();
}
@Test
public void multipleProfile_shouldInitWithWorkProfileUserHandle() {
- final int id1 = 1;
- final int id2 = 2;
- final UserInfo managedUser = new UserInfo(id2, "user 2", FLAG_MANAGED_PROFILE);
- final List<UserHandle> infos = new ArrayList<>();
- infos.add(new UserHandle(id1));
- infos.add(new UserHandle(id2));
- when(mUserManager.getUserProfiles()).thenReturn(infos);
- when(mUserManager.getUserHandle()).thenReturn(id1);
- when(mUserManager.getUserInfo(id2)).thenReturn(managedUser);
+ when(mUserManager.isManagedProfile()).thenReturn(false);
+ when(mUserManager.isLinkedUser()).thenReturn(false);
+
+ final List<UserInfo> infos = new ArrayList<>();
+ infos.add(new UserInfo(UserHandle.USER_SYSTEM, "user 1", 0 /* flags */));
+ infos.add(new UserInfo(
+ MANAGED_PROFILE_ID, "work profile", UserInfo.FLAG_MANAGED_PROFILE));
+ when(mUserManager.getProfiles(eq(UserHandle.USER_SYSTEM))).thenReturn(infos);
mController = new AutoSyncWorkDataPreferenceController(mContext, mFragment);
- assertThat(mController.mUserHandle.getIdentifier()).isEqualTo(id2);
+ assertThat(mController.mUserHandle.getIdentifier()).isEqualTo(MANAGED_PROFILE_ID);
+ assertThat(mController.isAvailable()).isTrue();
}
}
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.core.lifecycle.Lifecycle;
import org.junit.Before;
private @Mock Preference mPreference;
private @Mock PreferenceScreen mScreen;
private @Mock Lifecycle mLifecycle;
+ private @Mock PreferenceAvailabilityObserver mObserver;
private boolean mIsAvailable;
private Preference mUpdatedPreference = null;
assertThat(mUpdatedPreference).isEqualTo(mPreference);
}
+ @Test
+ public void testNotifyOnAvailabilityUpdate() {
+ final DynamicAvailabilityPreferenceController controller
+ = new DynamicAvailabilityPreferenceControllerTestable(mLifecycle);
+ controller.setAvailabilityObserver(mObserver);
+ assertThat(controller.getAvailabilityObserver()).isEqualTo(mObserver);
+
+ mIsAvailable = false;
+ controller.isAvailable();
+ verify(mObserver).onPreferenceAvailabilityUpdated(PREFERENCE_KEY, false);
+
+ mIsAvailable = true;
+ controller.isAvailable();
+ verify(mObserver).onPreferenceAvailabilityUpdated(PREFERENCE_KEY, true);
+ }
private class DynamicAvailabilityPreferenceControllerTestable
extends DynamicAvailabilityPreferenceController {
@Override
public boolean isAvailable() {
+ notifyOnAvailabilityUpdate(mIsAvailable);
return mIsAvailable;
}
import com.android.settings.R;
import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.mockito.stubbing.Answer;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
protected Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
protected AdminGrantedPermissionsPreferenceControllerBase mController;
FakeFeatureFactory.setupForTest(mContext);
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mController = createController(true /* async */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
private void setNumberOfPackagesWithAdminGrantedPermissions(int number, boolean async) {
setNumberOfPackagesWithAdminGrantedPermissions(0, true /* async */);
mController.updateState(preference);
assertThat(preference.isVisible()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(mKey, false);
setNumberOfPackagesWithAdminGrantedPermissions(20, true /* async */);
when(mContext.getResources().getQuantityString(
mController.updateState(preference);
assertThat(preference.getSummary()).isEqualTo("minimum 20 apps");
assertThat(preference.isVisible()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(mKey, true);
}
@Test
public void testIsAvailableSync() {
final AdminGrantedPermissionsPreferenceControllerBase controller
= createController(false /* async */);
+ controller.setAvailabilityObserver(mObserver);
setNumberOfPackagesWithAdminGrantedPermissions(0, false /* async */);
assertThat(controller.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(mKey, false);
setNumberOfPackagesWithAdminGrantedPermissions(20, false /* async */);
assertThat(controller.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(mKey, true);
}
@Test
public void testIsAvailableAsync() {
setNumberOfPackagesWithAdminGrantedPermissions(0, true /* async */);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(eq(mKey), anyBoolean());
setNumberOfPackagesWithAdminGrantedPermissions(20, true /* async */);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(eq(mKey), anyBoolean());
}
@Test
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class AlwaysOnVpnCurrentUserPreferenceControllerTest {
- private final String VPN_SET_DEVICE = "VPN set";
- private final String VPN_SET_PERSONAL = "VPN set in personal profile";
+ private static final String VPN_SET_DEVICE = "VPN set";
+ private static final String VPN_SET_PERSONAL = "VPN set in personal profile";
+ private static final String KEY_ALWAYS_ON_VPN_PRIMARY_USER = "always_on_vpn_primary_user";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private AlwaysOnVpnCurrentUserPreferenceController mController;
.thenReturn(VPN_SET_DEVICE);
when(mContext.getString(R.string.enterprise_privacy_always_on_vpn_personal))
.thenReturn(VPN_SET_PERSONAL);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
@Test
when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInCurrentUser())
.thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_ALWAYS_ON_VPN_PRIMARY_USER, false);
when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInCurrentUser())
.thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_ALWAYS_ON_VPN_PRIMARY_USER, true);
}
@Test
@Test
public void testGetPreferenceKey() {
- assertThat(mController.getPreferenceKey()).isEqualTo("always_on_vpn_primary_user");
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_ALWAYS_ON_VPN_PRIMARY_USER);
}
}
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class AlwaysOnVpnManagedProfilePreferenceControllerTest {
+ private static final String KEY_ALWAYS_ON_VPN_MANAGED_PROFILE = "always_on_vpn_managed_profile";
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private AlwaysOnVpnManagedProfilePreferenceController mController;
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mController = new AlwaysOnVpnManagedProfilePreferenceController(mContext,
null /* lifecycle */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
@Test
when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInManagedProfile())
.thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_ALWAYS_ON_VPN_MANAGED_PROFILE, false);
when(mFeatureFactory.enterprisePrivacyFeatureProvider.isAlwaysOnVpnSetInManagedProfile())
.thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_ALWAYS_ON_VPN_MANAGED_PROFILE, true);
}
@Test
@Test
public void testGetPreferenceKey() {
- assertThat(mController.getPreferenceKey()).isEqualTo("always_on_vpn_managed_profile");
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_ALWAYS_ON_VPN_MANAGED_PROFILE);
}
}
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class CaCertsPreferenceControllerTest {
+ private static final String KEY_CA_CERTS = "ca_certs";
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private CaCertsPreferenceController mController;
FakeFeatureFactory.setupForTest(mContext);
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mController = new CaCertsPreferenceController(mContext, null /* lifecycle */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
@Test
when(mFeatureFactory.enterprisePrivacyFeatureProvider
.getNumberOfOwnerInstalledCaCertsForCurrentUserAndManagedProfile()).thenReturn(0);
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_CA_CERTS, false);
when(mFeatureFactory.enterprisePrivacyFeatureProvider
.getNumberOfOwnerInstalledCaCertsForCurrentUserAndManagedProfile()).thenReturn(10);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_CA_CERTS, true);
}
@Test
@Test
public void testGetPreferenceKey() {
- assertThat(mController.getPreferenceKey()).isEqualTo("ca_certs");
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_CA_CERTS);
}
}
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
import com.android.settings.applications.ApplicationFeatureProvider;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyObject;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class EnterpriseInstalledPackagesPreferenceControllerTest {
+ private static final String KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES
+ = "number_enterprise_installed_packages";
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private EnterpriseInstalledPackagesPreferenceController mController;
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mController = new EnterpriseInstalledPackagesPreferenceController(mContext,
null /* lifecycle */, true /* async */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
private void setNumberOfEnterpriseInstalledPackages(int number, boolean async) {
setNumberOfEnterpriseInstalledPackages(0, true /* async */);
mController.updateState(preference);
assertThat(preference.isVisible()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES,
+ false);
setNumberOfEnterpriseInstalledPackages(20, true /* async */);
when(mContext.getResources().getQuantityString(
mController.updateState(preference);
assertThat(preference.getSummary()).isEqualTo("minimum 20 apps");
assertThat(preference.isVisible()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES,
+ true);
}
@Test
final EnterpriseInstalledPackagesPreferenceController controller
= new EnterpriseInstalledPackagesPreferenceController(mContext,
null /* lifecycle */, false /* async */);
+ controller.setAvailabilityObserver(mObserver);
setNumberOfEnterpriseInstalledPackages(0, false /* async */);
assertThat(controller.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(
+ KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES, false);
setNumberOfEnterpriseInstalledPackages(20, false /* async */);
assertThat(controller.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(
+ KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES, true);
}
@Test
public void testIsAvailableAsync() {
setNumberOfEnterpriseInstalledPackages(0, true /* async */);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES), anyBoolean());
setNumberOfEnterpriseInstalledPackages(20, true /* async */);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES), anyBoolean());
}
@Test
@Test
public void testGetPreferenceKey() {
assertThat(mController.getPreferenceKey())
- .isEqualTo("number_enterprise_installed_packages");
+ .isEqualTo(KEY_NUMBER_ENTERPRISE_INSTALLED_PACKAGES);
}
}
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class EnterprisePrivacyPreferenceControllerTest {
- private final String MANAGED_GENERIC = "managed by organization";
- private final String MANAGED_WITH_NAME = "managed by Foo, Inc.";
- private final String MANAGING_ORGANIZATION = "Foo, Inc.";
+ private static final String MANAGED_GENERIC = "managed by organization";
+ private static final String MANAGED_WITH_NAME = "managed by Foo, Inc.";
+ private static final String MANAGING_ORGANIZATION = "Foo, Inc.";
+ private static final String KEY_ENTERPRISE_PRIVACY = "enterprise_privacy";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private EnterprisePrivacyPreferenceController mController;
FakeFeatureFactory.setupForTest(mContext);
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mController = new EnterprisePrivacyPreferenceController(mContext, null /* lifecycle */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
@Test
public void testIsAvailable() {
when(mFeatureFactory.enterprisePrivacyFeatureProvider.hasDeviceOwner()).thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_ENTERPRISE_PRIVACY, false);
when(mFeatureFactory.enterprisePrivacyFeatureProvider.hasDeviceOwner()).thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
-
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_ENTERPRISE_PRIVACY, true);
}
@Test
@Test
public void testGetPreferenceKey() {
- assertThat(mController.getPreferenceKey()).isEqualTo("enterprise_privacy");
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_ENTERPRISE_PRIVACY);
}
}
package com.android.settings.enterprise;
+import android.app.Application;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.DynamicAvailabilityPreferenceController;
import com.android.settings.core.PreferenceController;
import com.android.settings.testutils.FakeFeatureFactory;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
+import org.xmlpull.v1.XmlPullParser;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class EnterprisePrivacySettingsTest {
+ private final static String RESOURCES_NAMESPACE = "http://schemas.android.com/apk/res/android";
+ private final static String ATTR_KEY = "key";
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
}
@Test
- public void getPreferenceControllers() {
+ public void getPreferenceControllers() throws Exception {
final List<PreferenceController> controllers = mSettings.getPreferenceControllers(
ShadowApplication.getInstance().getApplicationContext());
verifyPreferenceControllers(controllers);
}
@Test
- public void getSearchIndexProviderPreferenceControllers() {
+ public void getSearchIndexProviderPreferenceControllers() throws Exception {
final List<PreferenceController> controllers
= EnterprisePrivacySettings.SEARCH_INDEX_DATA_PROVIDER.getPreferenceControllers(
ShadowApplication.getInstance().getApplicationContext());
verifyPreferenceControllers(controllers);
}
- private void verifyPreferenceControllers(List<PreferenceController> controllers) {
+ private void verifyPreferenceControllers(List<PreferenceController> controllers)
+ throws Exception {
assertThat(controllers).isNotNull();
- assertThat(controllers.size()).isEqualTo(15);
+ assertThat(controllers.size()).isEqualTo(16);
int position = 0;
assertThat(controllers.get(position++)).isInstanceOf(NetworkLogsPreferenceController.class);
assertThat(controllers.get(position++)).isInstanceOf(BugReportsPreferenceController.class);
AlwaysOnVpnCurrentUserPreferenceController.class);
assertThat(controllers.get(position++)).isInstanceOf(
AlwaysOnVpnManagedProfilePreferenceController.class);
+ assertThat(controllers.get(position++)).isInstanceOf(ImePreferenceController.class);
assertThat(controllers.get(position++)).isInstanceOf(
GlobalHttpProxyPreferenceController.class);
assertThat(controllers.get(position++)).isInstanceOf(
CaCertsPreferenceController.class);
+ final PreferenceController exposureChangesCategoryController = controllers.get(position);
+ final int exposureChangesCategoryControllerIndex = position;
+ assertThat(controllers.get(position++)).isInstanceOf(
+ ExposureChangesCategoryPreferenceController.class);
assertThat(controllers.get(position++)).isInstanceOf(
FailedPasswordWipeCurrentUserPreferenceController.class);
assertThat(controllers.get(position++)).isInstanceOf(
FailedPasswordWipeManagedProfilePreferenceController.class);
- assertThat(controllers.get(position++)).isInstanceOf(ImePreferenceController.class);
+
+ // The "Changes made by your organization's admin" category is hidden when all Preferences
+ // inside it become unavailable. To do this correctly, the category's controller must:
+ // a) Observe the availability of all Preferences in the category and
+ // b) Be listed after those Preferences' controllers, so that availability is updated in
+ // the correct order
+
+ // Find all Preferences in the category.
+ final XmlResourceParser parser = RuntimeEnvironment.application.getResources().getXml(
+ R.xml.enterprise_privacy_settings);
+ boolean done = false;
+ int type;
+ final Set<String> expectedObserved = new HashSet<>();
+ while (!done && (type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type != XmlPullParser.START_TAG || !"exposure_changes_category".equals(
+ parser.getAttributeValue(RESOURCES_NAMESPACE, ATTR_KEY))) {
+ continue;
+ }
+ int depth = 1;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ if (type == XmlPullParser.START_TAG) {
+ final String key = parser.getAttributeValue(RESOURCES_NAMESPACE, ATTR_KEY);
+ if (key != null) {
+ expectedObserved.add(key);
+ }
+ depth++;
+ } else if (type == XmlPullParser.END_TAG) {
+ depth--;
+ if (depth == 0) {
+ done = true;
+ break;
+ }
+ }
+ }
+ }
+
+ // Find all Preferences the category's controller is observing.
+ final Set<String> actualObserved = new HashSet<>();
+ int maxObservedIndex = -1;
+ for (int i = 0; i < controllers.size(); i++) {
+ final PreferenceController controller = controllers.get(i);
+ if (controller instanceof DynamicAvailabilityPreferenceController &&
+ ((DynamicAvailabilityPreferenceController) controller).getAvailabilityObserver()
+ == exposureChangesCategoryController) {
+ actualObserved.add(controller.getPreferenceKey());
+ maxObservedIndex = i;
+ }
+ }
+
+ // Verify that the category's controller is observing the Preferences inside it.
+ assertThat(actualObserved).isEqualTo(expectedObserved);
+ // Verify that the category's controller is listed after the Preferences' controllers.
+ assertThat(maxObservedIndex).isLessThan(exposureChangesCategoryControllerIndex);
}
}
import com.android.settings.TestConfig;
import com.android.settings.applications.EnterpriseDefaultApps;
import com.android.settings.applications.UserAppInfo;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class EnterpriseSetDefaultAppsPreferenceControllerTest {
+ private static final String KEY_DEFAULT_APPS = "number_enterprise_set_default_apps";
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private UserManager mUm;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private EnterpriseSetDefaultAppsPreferenceController mController;
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mController = new EnterpriseSetDefaultAppsPreferenceController(mContext,
null /* lifecycle */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
private void setEnterpriseSetDefaultApps(Intent[] intents, int number) {
when(mFeatureFactory.applicationFeatureProvider.findPersistentPreferredActivities(anyInt(),
anyObject())).thenReturn(new ArrayList<UserAppInfo>());
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_DEFAULT_APPS, false);
setEnterpriseSetDefaultApps(EnterpriseDefaultApps.BROWSER.getIntents(), 1);
configureUsers(1);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_DEFAULT_APPS, true);
}
@Test
@Test
public void testGetPreferenceKey() {
- assertThat(mController.getPreferenceKey())
- .isEqualTo("number_enterprise_set_default_apps");
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_DEFAULT_APPS);
}
private static class MatchesIntents extends ArgumentMatcher<Intent[]> {
--- /dev/null
+/*
+ * 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.enterprise;
+
+import android.content.Context;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.core.DynamicAvailabilityPreferenceController;
+import com.android.settings.core.PreferenceAvailabilityObserver;
+
+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.annotation.Config;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+/**
+ * Tests for {@link ExposureChangesCategoryPreferenceController}.
+ */
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public final class ExposureChangesCategoryPreferenceControllerTest {
+
+ private static final String KEY_1 = "key_1";
+ private static final String KEY_2 = "key_2";
+ private static final String KEY_EXPOSURE_CHANGES_CATEGORY = "exposure_changes_category";
+
+ @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+ private Context mContext;
+ private List<DynamicAvailabilityPreferenceController> mControllers;
+ private ExposureChangesCategoryPreferenceController mController;
+ @Mock private PreferenceAvailabilityObserver mObserver;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mControllers = Arrays.asList(mock(DynamicAvailabilityPreferenceController.class),
+ mock(DynamicAvailabilityPreferenceController.class));
+ mController = new ExposureChangesCategoryPreferenceController(mContext,
+ null /* lifecycle */, mControllers, true /* controllingUi */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testInitialization() {
+ verify(mControllers.get(0)).setAvailabilityObserver(mController);
+ verify(mControllers.get(1)).setAvailabilityObserver(mController);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
+ }
+
+ @Test
+ public void testOnPreferenceAvailabilityUpdated() {
+ final Preference preference = new Preference(mContext, null, 0, 0);
+ preference.setVisible(true);
+
+ mController.updateState(preference);
+ assertThat(preference.isVisible()).isFalse();
+
+ mController.onPreferenceAvailabilityUpdated(KEY_1, true);
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, true);
+ assertThat(preference.isVisible()).isTrue();
+ reset(mObserver);
+
+ mController.onPreferenceAvailabilityUpdated(KEY_2, true);
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, true);
+ assertThat(preference.isVisible()).isTrue();
+ reset(mObserver);
+
+ mController.onPreferenceAvailabilityUpdated(KEY_1, false);
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, true);
+ assertThat(preference.isVisible()).isTrue();
+ reset(mObserver);
+
+ mController.onPreferenceAvailabilityUpdated(KEY_2, false);
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, false);
+ assertThat(preference.isVisible()).isFalse();
+ }
+
+ @Test
+ public void testUpdateState() {
+ final Preference preference = new Preference(mContext, null, 0, 0);
+ preference.setVisible(false);
+
+ mController.onPreferenceAvailabilityUpdated(KEY_1, true);
+ mController.updateState(preference);
+ assertThat(preference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void testIsAvailableForUi() {
+ assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_EXPOSURE_CHANGES_CATEGORY), anyBoolean());
+
+ mController.onPreferenceAvailabilityUpdated(KEY_1, true);
+ reset(mObserver);
+ assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_EXPOSURE_CHANGES_CATEGORY), anyBoolean());
+
+ mController.onPreferenceAvailabilityUpdated(KEY_1, false);
+ reset(mObserver);
+ assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_EXPOSURE_CHANGES_CATEGORY), anyBoolean());
+ }
+
+ @Test
+ public void testIsAvailableForSearch() {
+ final ExposureChangesCategoryPreferenceController controller
+ = new ExposureChangesCategoryPreferenceController(mContext, null /* lifecycle */,
+ mControllers, false /* controllingUi */);
+ controller.setAvailabilityObserver(mObserver);
+ verify(mControllers.get(0)).setAvailabilityObserver(controller);
+ verify(mControllers.get(1)).setAvailabilityObserver(controller);
+
+ assertThat(controller.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, false);
+ reset(mObserver);
+
+ controller.onPreferenceAvailabilityUpdated(KEY_1, true);
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_EXPOSURE_CHANGES_CATEGORY), anyBoolean());
+ assertThat(controller.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, true);
+ reset(mObserver);
+
+ controller.onPreferenceAvailabilityUpdated(KEY_2, true);
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_EXPOSURE_CHANGES_CATEGORY), anyBoolean());
+ assertThat(controller.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, true);
+ reset(mObserver);
+
+ controller.onPreferenceAvailabilityUpdated(KEY_1, false);
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_EXPOSURE_CHANGES_CATEGORY), anyBoolean());
+ assertThat(controller.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, true);
+ reset(mObserver);
+
+ controller.onPreferenceAvailabilityUpdated(KEY_2, false);
+ verify(mObserver, never()).onPreferenceAvailabilityUpdated(
+ eq(KEY_EXPOSURE_CHANGES_CATEGORY), anyBoolean());
+ assertThat(controller.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_EXPOSURE_CHANGES_CATEGORY, false);
+ }
+
+ @Test
+ public void testHandlePreferenceTreeClick() {
+ assertThat(mController.handlePreferenceTreeClick(new Preference(mContext, null, 0, 0)))
+ .isFalse();
+ }
+
+ @Test
+ public void testGetPreferenceKey() {
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_EXPOSURE_CHANGES_CATEGORY);
+ }
+}
import android.support.v7.preference.Preference;
import com.android.settings.R;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.mockito.MockitoAnnotations;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
protected Context mContext;
protected FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
protected FailedPasswordWipePreferenceControllerBase mController;
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
}
+ @Test
+ public void testGetAvailabilityObserver() {
+ mController.setAvailabilityObserver(mObserver);
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
+ }
+
public abstract void setMaximumFailedPasswordsBeforeWipe(int maximum);
@Test
@Test
public void testIsAvailable() {
+ mController.setAvailabilityObserver(mObserver);
+
setMaximumFailedPasswordsBeforeWipe(0);
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(mKey, false);
setMaximumFailedPasswordsBeforeWipe(10);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(mKey, true);
}
@Test
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class GlobalHttpProxyPreferenceControllerTest {
+
+ private static final String KEY_GLOBAL_HTTP_PROXY = "global_http_proxy";
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private GlobalHttpProxyPreferenceController mController;
FakeFeatureFactory.setupForTest(mContext);
mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext);
mController = new GlobalHttpProxyPreferenceController(mContext, null /* lifecycle */);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
@Test
when(mFeatureFactory.enterprisePrivacyFeatureProvider.isGlobalHttpProxySet())
.thenReturn(false);
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_GLOBAL_HTTP_PROXY, false);
when(mFeatureFactory.enterprisePrivacyFeatureProvider.isGlobalHttpProxySet())
.thenReturn(true);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_GLOBAL_HTTP_PROXY, true);
}
@Test
@Test
public void testGetPreferenceKey() {
- assertThat(mController.getPreferenceKey()).isEqualTo("global_http_proxy");
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_GLOBAL_HTTP_PROXY);
}
}
import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig;
+import com.android.settings.core.PreferenceAvailabilityObserver;
import com.android.settings.testutils.FakeFeatureFactory;
import org.junit.Before;
import org.robolectric.annotation.Config;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class ImePreferenceControllerTest {
- private final String DEFAULT_IME_LABEL = "Test IME";
- private final String DEFAULT_IME_TEXT = "Set to Test IME";
+ private static final String DEFAULT_IME_LABEL = "Test IME";
+ private static final String DEFAULT_IME_TEXT = "Set to Test IME";
+ private static final String KEY_INPUT_METHOD = "input_method";
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Context mContext;
private FakeFeatureFactory mFeatureFactory;
+ @Mock private PreferenceAvailabilityObserver mObserver;
private ImePreferenceController mController;
mController = new ImePreferenceController(mContext, null /* lifecycle */);
when(mContext.getResources().getString(R.string.enterprise_privacy_input_method_name,
DEFAULT_IME_LABEL)).thenReturn(DEFAULT_IME_TEXT);
+ mController.setAvailabilityObserver(mObserver);
+ }
+
+ @Test
+ public void testGetAvailabilityObserver() {
+ assertThat(mController.getAvailabilityObserver()).isEqualTo(mObserver);
}
@Test
when(mFeatureFactory.enterprisePrivacyFeatureProvider.getImeLabelIfOwnerSet())
.thenReturn(null);
assertThat(mController.isAvailable()).isFalse();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_INPUT_METHOD, false);
when(mFeatureFactory.enterprisePrivacyFeatureProvider.getImeLabelIfOwnerSet())
.thenReturn(DEFAULT_IME_LABEL);
assertThat(mController.isAvailable()).isTrue();
+ verify(mObserver).onPreferenceAvailabilityUpdated(KEY_INPUT_METHOD, true);
}
@Test
@Test
public void testGetPreferenceKey() {
- assertThat(mController.getPreferenceKey()).isEqualTo("input_method");
+ assertThat(mController.getPreferenceKey()).isEqualTo(KEY_INPUT_METHOD);
}
}
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
private static final String MAC_ADDRESS = WifiInfo.DEFAULT_MAC_ADDRESS;
private static final String SECURITY = "None";
- private InetAddress mIpv4Address;
- private Inet6Address mIpv6Address;
-
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private PreferenceScreen mockScreen;
@Mock private WifiDetailPreference mockSubnetPref;
@Mock private WifiDetailPreference mockDnsPref;
@Mock private Button mockForgetButton;
- @Mock private PreferenceCategory mockIpv6AddressCategory;
+ @Mock private PreferenceCategory mockIpv6Category;
+ @Mock private WifiDetailPreference mockIpv6AddressesPref;
@Captor private ArgumentCaptor<NetworkCallback> mCallbackCaptor;
@Captor private ArgumentCaptor<View.OnClickListener> mForgetClickListener;
+ @Captor private ArgumentCaptor<Preference> mIpv6AddressCaptor;
private Context mContext = RuntimeEnvironment.application;
private Lifecycle mLifecycle;
private LinkProperties mLinkProperties;
private WifiDetailPreferenceController mController;
+ // This class exists so that these values can be made static final. They can't be static final
+ // members of the test class, because any attempt to call IpPrefix or RouteInfo constructors
+ // during static initialization of the test class results in NoSuchMethorError being thrown
+ // when the test is run.
+ private static class Constants {
+ static final int IPV4_PREFIXLEN = 25;
+ static final LinkAddress IPV4_ADDR;
+ static final Inet4Address IPV4_GATEWAY;
+ static final RouteInfo IPV4_DEFAULT;
+ static final RouteInfo IPV4_SUBNET;
+ static final LinkAddress IPV6_LINKLOCAL;
+ static final LinkAddress IPV6_GLOBAL1;
+ static final LinkAddress IPV6_GLOBAL2;
+ static final InetAddress IPV4_DNS1;
+ static final InetAddress IPV4_DNS2;
+ static final InetAddress IPV6_DNS;
+
+ private static LinkAddress ipv6LinkAddress(String addr) throws UnknownHostException {
+ return new LinkAddress(InetAddress.getByName(addr), 64);
+ }
+
+ private static LinkAddress ipv4LinkAddress(String addr, int prefixlen)
+ throws UnknownHostException {
+ return new LinkAddress(InetAddress.getByName(addr), prefixlen);
+ }
+
+ static {
+ try {
+ // We create our test constants in these roundabout ways because the robolectric
+ // shadows don't contain NetworkUtils.parseNumericAddress and other utility methods,
+ // so the easy ways to do things fail with NoSuchMethodError.
+ IPV4_ADDR = ipv4LinkAddress("192.0.2.2", IPV4_PREFIXLEN);
+ IPV4_GATEWAY = (Inet4Address) InetAddress.getByName("192.0.2.127");
+
+ final Inet4Address any4 = (Inet4Address) InetAddress.getByName("0.0.0.0");
+ IpPrefix subnet = new IpPrefix(IPV4_ADDR.getAddress(), IPV4_PREFIXLEN);
+ IPV4_SUBNET = new RouteInfo(subnet, any4);
+ IPV4_DEFAULT = new RouteInfo(new IpPrefix(any4, 0), IPV4_GATEWAY);
+
+ IPV6_LINKLOCAL = ipv6LinkAddress("fe80::211:25ff:fef8:7cb2%1");
+ IPV6_GLOBAL1 = ipv6LinkAddress("2001:db8:1::211:25ff:fef8:7cb2");
+ IPV6_GLOBAL2 = ipv6LinkAddress("2001:db8:1::3dfe:8902:f98f:739d");
+
+ IPV4_DNS1 = InetAddress.getByName("8.8.8.8");
+ IPV4_DNS2 = InetAddress.getByName("8.8.4.4");
+ IPV6_DNS = InetAddress.getByName("2001:4860:4860::64");
+ } catch (UnknownHostException e) {
+ throw new RuntimeException("Invalid hardcoded IP addresss: " + e);
+ }
+ }
+ }
+
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mLifecycle = new Lifecycle();
- try {
- mIpv4Address = InetAddress.getByAddress(
- new byte[] { (byte) 255, (byte) 255, (byte) 255, (byte) 255 });
- mIpv6Address = Inet6Address.getByAddress(
- "123", /* host */
- new byte[] {
- (byte) 0xFE, (byte) 0x80, 0, 0, 0, 0, 0, 0, 0x02, 0x11, 0x25,
- (byte) 0xFF, (byte) 0xFE, (byte) 0xF8, (byte) 0x7C, (byte) 0xB2},
- 1 /*scope id */);
- } catch (UnknownHostException e) {
- throw new RuntimeException(e);
- }
-
when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfig);
when(mockAccessPoint.getLevel()).thenReturn(LEVEL);
when(mockAccessPoint.getSecurityString(false)).thenReturn(SECURITY);
.thenReturn(mockSubnetPref);
when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_DNS_PREF))
.thenReturn(mockDnsPref);
- when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESS_CATEGORY))
- .thenReturn(mockIpv6AddressCategory);
+ when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_CATEGORY))
+ .thenReturn(mockIpv6Category);
+ when(mockScreen.findPreference(WifiDetailPreferenceController.KEY_IPV6_ADDRESSES_PREF))
+ .thenReturn(mockIpv6AddressesPref);
}
@Test
@Test
public void ipAddressPref_shouldHaveDetailTextSet() {
- LinkAddress ipv4Address = new LinkAddress(mIpv4Address, 32);
-
- mLinkProperties.addLinkAddress(ipv4Address);
+ mLinkProperties.addLinkAddress(Constants.IPV4_ADDR);
mController.displayPreference(mockScreen);
- verify(mockIpAddressPref).setDetailText(mIpv4Address.getHostAddress());
+ verify(mockIpAddressPref).setDetailText(Constants.IPV4_ADDR.getAddress().getHostAddress());
}
@Test
public void gatewayAndSubnet_shouldHaveDetailTextSet() {
- int prefixLength = 24;
- IpPrefix subnet = new IpPrefix(mIpv4Address, prefixLength);
- InetAddress gateway = mIpv4Address;
- mLinkProperties.addRoute(new RouteInfo(subnet, gateway));
+ mLinkProperties.addLinkAddress(Constants.IPV4_ADDR);
+ mLinkProperties.addRoute(Constants.IPV4_DEFAULT);
+ mLinkProperties.addRoute(Constants.IPV4_SUBNET);
mController.displayPreference(mockScreen);
- verify(mockSubnetPref).setDetailText("255.255.255.0");
- verify(mockGatewayPref).setDetailText(mIpv4Address.getHostAddress());
+ verify(mockSubnetPref).setDetailText("255.255.255.128");
+ verify(mockGatewayPref).setDetailText("192.0.2.127");
}
@Test
@Test
public void noLinkProperties_allIpDetailsHidden() {
when(mockConnectivityManager.getLinkProperties(mockNetwork)).thenReturn(null);
- reset(mockIpv6AddressCategory, mockIpAddressPref, mockSubnetPref, mockGatewayPref,
+ reset(mockIpv6Category, mockIpAddressPref, mockSubnetPref, mockGatewayPref,
mockDnsPref);
mController.displayPreference(mockScreen);
- verify(mockIpv6AddressCategory).setVisible(false);
+ verify(mockIpv6Category).setVisible(false);
verify(mockIpAddressPref).setVisible(false);
verify(mockSubnetPref).setVisible(false);
verify(mockGatewayPref).setVisible(false);
verify(mockDnsPref).setVisible(false);
- verify(mockIpv6AddressCategory, never()).setVisible(true);
+ verify(mockIpv6Category, never()).setVisible(true);
verify(mockIpAddressPref, never()).setVisible(true);
verify(mockSubnetPref, never()).setVisible(true);
verify(mockGatewayPref, never()).setVisible(true);
verify(mockDnsPref, never()).setVisible(true);
}
+ // Convenience method to convert a LinkAddress to a string without a prefix length.
+ private String asString(LinkAddress l) {
+ return l.getAddress().getHostAddress();
+ }
+
+ // Pretend that the NetworkCallback was triggered with a new copy of lp. We need to create a
+ // new copy because the code only updates if !mLinkProperties.equals(lp).
+ private void updateLinkProperties(LinkProperties lp) {
+ mCallbackCaptor.getValue().onLinkPropertiesChanged(mockNetwork, new LinkProperties(lp));
+ }
+
+ private void verifyDisplayedIpv6Addresses(InOrder inOrder, LinkAddress... addresses) {
+ String text = Arrays.stream(addresses)
+ .map(address -> asString(address))
+ .collect(Collectors.joining("\n"));
+ inOrder.verify(mockIpv6AddressesPref).setSummary(text);
+ }
+
+ @Test
+ public void onLinkPropertiesChanged_updatesFields() {
+ mController.displayPreference(mockScreen);
+ mController.onResume();
+
+ InOrder inOrder = inOrder(mockIpAddressPref, mockGatewayPref, mockSubnetPref,
+ mockDnsPref, mockIpv6Category, mockIpv6AddressesPref);
+
+ LinkProperties lp = new LinkProperties();
+
+ lp.addLinkAddress(Constants.IPV6_LINKLOCAL);
+ updateLinkProperties(lp);
+ verifyDisplayedIpv6Addresses(inOrder, Constants.IPV6_LINKLOCAL);
+ inOrder.verify(mockIpv6Category).setVisible(true);
+
+ lp.addRoute(Constants.IPV4_DEFAULT);
+ updateLinkProperties(lp);
+ inOrder.verify(mockGatewayPref).setDetailText(Constants.IPV4_GATEWAY.getHostAddress());
+ inOrder.verify(mockGatewayPref).setVisible(true);
+
+ lp.addLinkAddress(Constants.IPV4_ADDR);
+ lp.addRoute(Constants.IPV4_SUBNET);
+ updateLinkProperties(lp);
+ inOrder.verify(mockIpAddressPref).setDetailText(asString(Constants.IPV4_ADDR));
+ inOrder.verify(mockIpAddressPref).setVisible(true);
+ inOrder.verify(mockSubnetPref).setDetailText("255.255.255.128");
+ inOrder.verify(mockSubnetPref).setVisible(true);
+
+ lp.addLinkAddress(Constants.IPV6_GLOBAL1);
+ lp.addLinkAddress(Constants.IPV6_GLOBAL2);
+ updateLinkProperties(lp);
+ verifyDisplayedIpv6Addresses(inOrder,
+ Constants.IPV6_LINKLOCAL,
+ Constants.IPV6_GLOBAL1,
+ Constants.IPV6_GLOBAL2);
+
+ lp.removeLinkAddress(Constants.IPV6_GLOBAL1);
+ updateLinkProperties(lp);
+ verifyDisplayedIpv6Addresses(inOrder,
+ Constants.IPV6_LINKLOCAL,
+ Constants.IPV6_GLOBAL2);
+
+ lp.addDnsServer(Constants.IPV6_DNS);
+ updateLinkProperties(lp);
+ inOrder.verify(mockDnsPref, never()).setVisible(true);
+
+ lp.addDnsServer(Constants.IPV4_DNS1);
+ lp.addDnsServer(Constants.IPV4_DNS2);
+ updateLinkProperties(lp);
+ inOrder.verify(mockDnsPref).setDetailText(
+ Constants.IPV4_DNS1.getHostAddress() + "," +
+ Constants.IPV4_DNS2.getHostAddress());
+ inOrder.verify(mockDnsPref).setVisible(true);
+ }
+
@Test
public void canForgetNetwork_noNetwork() {
when(mockAccessPoint.getConfig()).thenReturn(null);
@Test
public void ipv6AddressPref_shouldHaveHostAddressTextSet() {
- LinkAddress ipv6Address = new LinkAddress(mIpv6Address, 128);
-
- mLinkProperties.addLinkAddress(ipv6Address);
+ mLinkProperties.addLinkAddress(Constants.IPV6_LINKLOCAL);
+ mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL1);
+ mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2);
mController.displayPreference(mockScreen);
- ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class);
- verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture());
- assertThat(preferenceCaptor.getValue().getTitle()).isEqualTo(mIpv6Address.getHostAddress());
+ List <Preference> addrs = mIpv6AddressCaptor.getAllValues();
+
+ String expectedAddresses = String.join("\n",
+ asString(Constants.IPV6_LINKLOCAL),
+ asString(Constants.IPV6_GLOBAL1),
+ asString(Constants.IPV6_GLOBAL2));
+
+ verify(mockIpv6AddressesPref).setSummary(expectedAddresses);
}
@Test
public void ipv6AddressPref_shouldNotBeSelectable() {
- LinkAddress ipv6Address = new LinkAddress(mIpv6Address, 128);
-
- mLinkProperties.addLinkAddress(ipv6Address);
+ mLinkProperties.addLinkAddress(Constants.IPV6_GLOBAL2);
mController.displayPreference(mockScreen);
- ArgumentCaptor<Preference> preferenceCaptor = ArgumentCaptor.forClass(Preference.class);
- verify(mockIpv6AddressCategory).addPreference(preferenceCaptor.capture());
- assertThat(preferenceCaptor.getValue().isSelectable()).isFalse();
+ assertThat(mockIpv6AddressesPref.isSelectable()).isFalse();
}
@Test