diff --git a/Android.mk b/Android.mk index 6b0d077a214..f10b3ec2d08 100644 --- a/Android.mk +++ b/Android.mk @@ -41,6 +41,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ androidx.lifecycle_lifecycle-extensions \ guava \ jsr305 \ + contextualcards \ settings-logtags \ LOCAL_PROGUARD_FLAG_FILES := proguard.flags @@ -57,7 +58,14 @@ include frameworks/base/packages/SettingsLib/search/common.mk include $(BUILD_PACKAGE) +# ==== prebuilt library ======================== +include $(CLEAR_VARS) + +LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \ + contextualcards:libs/contextualcards.aar +include $(BUILD_MULTI_PREBUILT) + # Use the following include to make our test apk. ifeq (,$(ONE_SHOT_MAKEFILE)) include $(call all-makefiles-under,$(LOCAL_PATH)) -endif +endif \ No newline at end of file diff --git a/AndroidManifest.xml b/AndroidManifest.xml index aa53bdbdab0..94be61c9312 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3192,6 +3192,15 @@ android:exported="true" android:permission="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA" /> + + + + + diff --git a/libs/contextualcards.aar b/libs/contextualcards.aar new file mode 100755 index 00000000000..a44a26c38b1 Binary files /dev/null and b/libs/contextualcards.aar differ diff --git a/res/values/strings.xml b/res/values/strings.xml index 119e1fb7f43..90a46aebab5 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -384,15 +384,15 @@ Allow your phone to communicate with nearby Bluetooth devices - + Disable Bluetooth A2DP hardware offload - + Restart Device? - + You need to restart your device to change this setting. - + Restart - + Cancel diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml index 684d0325417..81afc1a11e3 100644 --- a/res/xml/app_info_settings.xml +++ b/res/xml/app_info_settings.xml @@ -67,6 +67,12 @@ android:summary="@string/summary_placeholder" settings:controller="com.android.settings.applications.appinfo.AppDataUsagePreferenceController" /> + + + android:selectable="false" + settings:allowDynamicSummaryInSlice="true" + settings:controller= + "com.android.settings.deviceinfo.PhoneNumberPreferenceController" /> mGroups = new ArrayMap<>(); - private final Context mContext; - private final PackageInfo mPackageInfo; - - public AppPermissions(Context context, String packageName) { - mContext = context; - mPackageInfo = getPackageInfo(packageName); - refresh(); - } - - private PackageInfo getPackageInfo(String packageName) { - try { - return mContext.getPackageManager().getPackageInfo(packageName, - PackageManager.GET_PERMISSIONS); - } catch (NameNotFoundException e) { - Log.e(TAG, "Unable to find " + packageName, e); - return null; - } - } - - public void refresh() { - if (mPackageInfo != null) { - loadPermissionGroups(); - } - } - - public int getPermissionCount() { - return mGroups.size(); - } - - public int getGrantedPermissionsCount() { - int ct = 0; - for (int i = 0; i < mGroups.size(); i++) { - if (mGroups.valueAt(i).areRuntimePermissionsGranted()) { - ct++; - } - } - return ct; - } - - private void loadPermissionGroups() { - mGroups.clear(); - if (mPackageInfo.requestedPermissions == null) { - return; - } - - final boolean appSupportsRuntimePermissions = appSupportsRuntime( - mPackageInfo.applicationInfo); - - for (int i = 0; i < mPackageInfo.requestedPermissions.length; i++) { - String requestedPerm = mPackageInfo.requestedPermissions[i]; - - final PermissionInfo permInfo; - try { - permInfo = mContext.getPackageManager().getPermissionInfo(requestedPerm, 0); - } catch (NameNotFoundException e) { - Log.w(TAG, "Unknown permission: " + requestedPerm); - continue; - } - - String permName = permInfo.name; - String groupName = permInfo.group != null ? permInfo.group : permName; - - PermissionGroup group = mGroups.get(groupName); - if (group == null) { - group = new PermissionGroup(); - mGroups.put(groupName, group); - } - - final boolean runtime = appSupportsRuntimePermissions - && permInfo.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS; - final boolean granted = (mPackageInfo.requestedPermissionsFlags[i] - & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0; - - Permission permission = new Permission(runtime, granted); - group.addPermission(permission, permName); - } - // Only care about runtime perms for now. - for (int i = mGroups.size() - 1; i >= 0; i--) { - if (!mGroups.valueAt(i).mHasRuntimePermissions) { - mGroups.removeAt(i); - } - } - } - - public static boolean appSupportsRuntime(ApplicationInfo info) { - return info.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1; - } - - private static final class PermissionGroup { - private final ArrayMap mPermissions = new ArrayMap<>(); - private boolean mHasRuntimePermissions; - - public boolean hasRuntimePermissions() { - return mHasRuntimePermissions; - } - - public boolean areRuntimePermissionsGranted() { - final int permissionCount = mPermissions.size(); - for (int i = 0; i < permissionCount; i++) { - Permission permission = mPermissions.valueAt(i); - if (permission.runtime && !permission.granted) { - return false; - } - } - return true; - } - - public List getPermissions() { - return new ArrayList<>(mPermissions.values()); - } - - void addPermission(Permission permission, String permName) { - mPermissions.put(permName, permission); - if (permission.runtime) { - mHasRuntimePermissions = true; - } - } - } - - private static final class Permission { - private final boolean runtime; - private boolean granted; - - public Permission(boolean runtime, boolean granted) { - this.runtime = runtime; - this.granted = granted; - } - } -} diff --git a/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java b/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java index a395f9833f0..1763d84491a 100644 --- a/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java +++ b/src/com/android/settings/applications/SpecialAppAccessPreferenceController.java @@ -23,6 +23,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settings.datausage.AppStateDataUsageBridge; +import com.android.settings.datausage.AppStateDataUsageBridge.DataUsageState; import com.android.settings.datausage.DataSaverBackend; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -108,8 +109,8 @@ public class SpecialAppAccessPreferenceController extends BasePreferenceControll if (!ApplicationsState.FILTER_DOWNLOADED_AND_LAUNCHER.filterApp(entry)) { continue; } - if (entry.extraInfo != null && ((AppStateDataUsageBridge.DataUsageState) - entry.extraInfo).isDataSaverWhitelisted) { + if (entry.extraInfo instanceof DataUsageState + && ((DataUsageState) entry.extraInfo).isDataSaverWhitelisted) { count++; } } diff --git a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java index 4337b88bd53..9443c9395a2 100644 --- a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceController.java @@ -25,6 +25,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.text.format.DateUtils; import android.text.format.Formatter; +import android.util.FeatureFlagUtils; import androidx.annotation.VisibleForTesting; import androidx.loader.app.LoaderManager; @@ -35,6 +36,7 @@ import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; +import com.android.settings.core.FeatureFlags; import com.android.settings.datausage.AppDataUsage; import com.android.settings.datausage.DataUsageList; import com.android.settings.datausage.DataUsageUtils; @@ -45,6 +47,12 @@ import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.net.ChartData; import com.android.settingslib.net.ChartDataLoaderCompat; +/** + * Deprecated in favor of {@link AppDataUsagePreferenceControllerV2} + * + * @deprecated + */ +@Deprecated public class AppDataUsagePreferenceController extends AppInfoPreferenceControllerBase implements LoaderManager.LoaderCallbacks, LifecycleObserver, OnResume, OnPause { @@ -57,6 +65,9 @@ public class AppDataUsagePreferenceController extends AppInfoPreferenceControlle @Override public int getAvailabilityStatus() { + if (FeatureFlagUtils.isEnabled(mContext, FeatureFlags.DATA_USAGE_V2)) { + return UNSUPPORTED_ON_DEVICE; + } return isBandwidthControlEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } @@ -93,7 +104,9 @@ public class AppDataUsagePreferenceController extends AppInfoPreferenceControlle @Override public void onPause() { - mParent.getLoaderManager().destroyLoader(mParent.LOADER_CHART_DATA); + if (mStatsSession != null) { + mParent.getLoaderManager().destroyLoader(mParent.LOADER_CHART_DATA); + } } @Override diff --git a/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2.java b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2.java new file mode 100644 index 00000000000..9bbc5c0935a --- /dev/null +++ b/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2.java @@ -0,0 +1,158 @@ +/* + * 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.applications.appinfo; + +import android.content.Context; +import android.net.NetworkTemplate; +import android.os.Bundle; +import android.text.format.DateUtils; +import android.text.format.Formatter; +import android.util.FeatureFlagUtils; + +import androidx.annotation.VisibleForTesting; +import androidx.loader.app.LoaderManager; +import androidx.loader.content.Loader; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.Utils; +import com.android.settings.core.FeatureFlags; +import com.android.settings.datausage.AppDataUsageV2; +import com.android.settings.datausage.DataUsageUtils; +import com.android.settingslib.AppItem; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnPause; +import com.android.settingslib.core.lifecycle.events.OnResume; +import com.android.settingslib.net.NetworkCycleDataForUid; +import com.android.settingslib.net.NetworkCycleDataForUidLoader; + +import java.util.List; + +public class AppDataUsagePreferenceControllerV2 extends AppInfoPreferenceControllerBase + implements LoaderManager.LoaderCallbacks>, LifecycleObserver, + OnResume, OnPause { + + private List mAppUsageData; + + public AppDataUsagePreferenceControllerV2(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + if (!FeatureFlagUtils.isEnabled(mContext, FeatureFlags.DATA_USAGE_V2)) { + return UNSUPPORTED_ON_DEVICE; + } + return isBandwidthControlEnabled() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + } + + @Override + public void updateState(Preference preference) { + preference.setSummary(getDataSummary()); + } + + @Override + public void onResume() { + if (isAvailable()) { + final int uid = mParent.getAppEntry().info.uid; + final AppItem app = new AppItem(uid); + app.addUid(uid); + mParent.getLoaderManager().restartLoader(mParent.LOADER_CHART_DATA, null /* args */, + this); + } + } + + @Override + public void onPause() { + if (isAvailable()) { + mParent.getLoaderManager().destroyLoader(mParent.LOADER_CHART_DATA); + } + } + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + final NetworkTemplate template = getTemplate(mContext); + return NetworkCycleDataForUidLoader.builder(mContext) + .setUid(mParent.getAppEntry().info.uid) + .setRetrieveDetail(false) + .setNetworkTemplate(template) + .setSubscriberId(template.getSubscriberId()) + .build(); + } + + @Override + public void onLoadFinished(Loader> loader, + List data) { + mAppUsageData = data; + updateState(mPreference); + } + + @Override + public void onLoaderReset(Loader> loader) { + // Leave last result. + } + + @Override + protected Class getDetailFragmentClass() { + return AppDataUsageV2.class; + } + + private CharSequence getDataSummary() { + if (mAppUsageData != null) { + long totalBytes = 0; + long startTime = System.currentTimeMillis(); + for (NetworkCycleDataForUid data : mAppUsageData) { + totalBytes += data.getTotalUsage(); + final long cycleStart = data.getStartTime(); + if (cycleStart < startTime) { + startTime = cycleStart; + } + } + if (totalBytes == 0) { + return mContext.getString(R.string.no_data_usage); + } + return mContext.getString(R.string.data_summary_format, + Formatter.formatFileSize(mContext, totalBytes), + DateUtils.formatDateTime(mContext, startTime, + DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH)); + } + return mContext.getString(R.string.computing_size); + } + + private static NetworkTemplate getTemplate(Context context) { + if (DataUsageUtils.hasReadyMobileRadio(context)) { + return NetworkTemplate.buildTemplateMobileWildcard(); + } + if (DataUsageUtils.hasWifiRadio(context)) { + return NetworkTemplate.buildTemplateWifiWildcard(); + } + return NetworkTemplate.buildTemplateEthernet(); + } + + @VisibleForTesting + boolean isBandwidthControlEnabled() { + return Utils.isBandwidthControlEnabled(); + } + +} diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 7b9cc796ab0..64fd36d2450 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -34,6 +34,7 @@ import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; +import android.util.FeatureFlagUtils; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; @@ -48,6 +49,7 @@ import com.android.settings.SettingsPreferenceFragment; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.applications.specialaccess.pictureinpicture .PictureInPictureDetailPreferenceController; +import com.android.settings.core.FeatureFlags; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; import com.android.settingslib.RestrictedLockUtilsInternal; @@ -139,7 +141,11 @@ public class AppInfoDashboardFragment extends DashboardFragment final String packageName = getPackageName(); use(TimeSpentInAppPreferenceController.class).setPackageName(packageName); - use(AppDataUsagePreferenceController.class).setParentFragment(this); + if (FeatureFlagUtils.isEnabled(context, FeatureFlags.DATA_USAGE_V2)) { + use(AppDataUsagePreferenceControllerV2.class).setParentFragment(this); + } else { + use(AppDataUsagePreferenceController.class).setParentFragment(this); + } final AppInstallerInfoPreferenceController installer = use(AppInstallerInfoPreferenceController.class); installer.setPackageName(packageName); diff --git a/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java index be41c0ff5cc..38e70d1ee17 100644 --- a/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java +++ b/src/com/android/settings/applications/appinfo/ExternalSourcesDetails.java @@ -80,21 +80,20 @@ public class ExternalSourcesDetails extends AppInfoWithHeader } public static CharSequence getPreferenceSummary(Context context, AppEntry entry) { + final UserHandle userHandle = UserHandle.getUserHandleForUid(entry.info.uid); final UserManager um = UserManager.get(context); final int userRestrictionSource = um.getUserRestrictionSource( - UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, - UserHandle.getUserHandleForUid(entry.info.uid)); - switch (userRestrictionSource) { - case UserManager.RESTRICTION_SOURCE_DEVICE_OWNER: - case UserManager.RESTRICTION_SOURCE_PROFILE_OWNER: - return context.getString(R.string.disabled_by_admin); - case UserManager.RESTRICTION_SOURCE_SYSTEM: - return context.getString(R.string.disabled); + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle) + | um.getUserRestrictionSource( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, + userHandle); + if ((userRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) { + return context.getString(R.string.disabled_by_admin); + } else if (userRestrictionSource != 0) { + return context.getString(R.string.disabled); } - final InstallAppsState appsState = new AppStateInstallAppsBridge(context, null, null) .createInstallAppsStateFor(entry.info.packageName, entry.info.uid); - return context.getString(appsState.canInstallApps() ? R.string.app_permission_summary_allowed : R.string.app_permission_summary_not_allowed); @@ -119,6 +118,10 @@ public class ExternalSourcesDetails extends AppInfoWithHeader return true; } mSwitchPref.checkRestrictionAndSetDisabled(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); + if (!mSwitchPref.isDisabledByAdmin()) { + mSwitchPref.checkRestrictionAndSetDisabled( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY); + } if (mSwitchPref.isDisabledByAdmin()) { return true; } diff --git a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java index e26f8813fca..9c4f964c7fd 100644 --- a/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java +++ b/src/com/android/settings/biometrics/face/FaceSettingsAttentionPreferenceController.java @@ -18,8 +18,8 @@ package com.android.settings.biometrics.face; import android.content.Context; import android.hardware.face.FaceManager; -import android.util.Log; +import com.android.settings.Utils; import com.android.settings.core.TogglePreferenceController; import androidx.preference.PreferenceScreen; @@ -39,7 +39,7 @@ public class FaceSettingsAttentionPreferenceController extends TogglePreferenceC public FaceSettingsAttentionPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); - mFaceManager = context.getSystemService(FaceManager.class); + mFaceManager = Utils.getFaceManagerOrNull(context); } public FaceSettingsAttentionPreferenceController(Context context) { diff --git a/src/com/android/settings/datausage/DataUsageListV2.java b/src/com/android/settings/datausage/DataUsageListV2.java index ea652b3138a..c6d3b4d23c3 100644 --- a/src/com/android/settings/datausage/DataUsageListV2.java +++ b/src/com/android/settings/datausage/DataUsageListV2.java @@ -426,11 +426,11 @@ public class DataUsageListV2 extends DataUsageBaseFragment { private void startAppDataUsage(AppItem item) { final Bundle args = new Bundle(); - args.putParcelable(AppDataUsage.ARG_APP_ITEM, item); - args.putParcelable(AppDataUsage.ARG_NETWORK_TEMPLATE, mTemplate); + args.putParcelable(AppDataUsageV2.ARG_APP_ITEM, item); + args.putParcelable(AppDataUsageV2.ARG_NETWORK_TEMPLATE, mTemplate); new SubSettingLauncher(getContext()) - .setDestination(AppDataUsage.class.getName()) + .setDestination(AppDataUsageV2.class.getName()) .setTitleRes(R.string.app_data_usage) .setArguments(args) .setSourceMetricsCategory(getMetricsCategory()) @@ -490,8 +490,6 @@ public class DataUsageListV2 extends DataUsageBaseFragment { @Override public Loader> onCreateLoader(int id, Bundle args) { return NetworkCycleChartDataLoader.builder(getContext()) - .setNetworkPolicy(services.mPolicyEditor.getPolicy(mTemplate)) - .setNetworkType(mNetworkType) .setNetworkTemplate(mTemplate) .setSubscriberId(mTelephonyManager.getSubscriberId(mSubId)) .build(); diff --git a/src/com/android/settings/datetime/timezone/TimeZoneInfoPreferenceController.java b/src/com/android/settings/datetime/timezone/TimeZoneInfoPreferenceController.java index 233111aa2f1..a819f101a87 100644 --- a/src/com/android/settings/datetime/timezone/TimeZoneInfoPreferenceController.java +++ b/src/com/android/settings/datetime/timezone/TimeZoneInfoPreferenceController.java @@ -17,10 +17,10 @@ package com.android.settings.datetime.timezone; import android.content.Context; -import android.icu.impl.OlsonTimeZone; import android.icu.text.DateFormat; import android.icu.text.DisplayContext; import android.icu.text.SimpleDateFormat; +import android.icu.util.BasicTimeZone; import android.icu.util.Calendar; import android.icu.util.TimeZone; import android.icu.util.TimeZoneTransition; @@ -115,17 +115,17 @@ public class TimeZoneInfoPreferenceController extends BaseTimeZonePreferenceCont } private TimeZoneTransition findNextDstTransition(TimeZone timeZone) { - if (!(timeZone instanceof OlsonTimeZone)) { + if (!(timeZone instanceof BasicTimeZone)) { return null; } - final OlsonTimeZone olsonTimeZone = (OlsonTimeZone) timeZone; - TimeZoneTransition transition = olsonTimeZone.getNextTransition( + final BasicTimeZone basicTimeZone = (BasicTimeZone) timeZone; + TimeZoneTransition transition = basicTimeZone.getNextTransition( mDate.getTime(), /* inclusive */ false); do { if (transition.getTo().getDSTSavings() != transition.getFrom().getDSTSavings()) { break; } - transition = olsonTimeZone.getNextTransition( + transition = basicTimeZone.getNextTransition( transition.getTime(), /*inclusive */ false); } while (transition != null); return transition; diff --git a/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java b/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java index 7670ef1e25b..d27af64d593 100644 --- a/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java +++ b/src/com/android/settings/development/featureflags/FeatureFlagPersistent.java @@ -23,6 +23,8 @@ import android.util.FeatureFlagUtils; import androidx.annotation.VisibleForTesting; +import androidx.annotation.VisibleForTesting; + import com.android.settings.core.FeatureFlags; import java.util.HashSet; diff --git a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java index 8e60b06fee2..6f5f346f89c 100644 --- a/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java +++ b/src/com/android/settings/deviceinfo/PhoneNumberPreferenceController.java @@ -29,15 +29,13 @@ import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; -import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.core.BasePreferenceController; import com.android.settingslib.DeviceInfoUtils; -import com.android.settingslib.core.AbstractPreferenceController; import java.util.ArrayList; import java.util.List; -public class PhoneNumberPreferenceController extends AbstractPreferenceController implements - PreferenceControllerMixin { +public class PhoneNumberPreferenceController extends BasePreferenceController { private final static String KEY_PHONE_NUMBER = "phone_number"; @@ -45,21 +43,20 @@ public class PhoneNumberPreferenceController extends AbstractPreferenceControlle private final SubscriptionManager mSubscriptionManager; private final List mPreferenceList = new ArrayList<>(); - public PhoneNumberPreferenceController(Context context) { - super(context); - mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - mSubscriptionManager = (SubscriptionManager) context.getSystemService( - Context.TELEPHONY_SUBSCRIPTION_SERVICE); + public PhoneNumberPreferenceController(Context context, String key) { + super(context, key); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); } @Override - public String getPreferenceKey() { - return KEY_PHONE_NUMBER; + public int getAvailabilityStatus() { + return mTelephonyManager.isVoiceCapable() ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override - public boolean isAvailable() { - return mTelephonyManager.isVoiceCapable(); + public CharSequence getSummary() { + return getFirstPhoneNumber(); } @Override @@ -89,10 +86,26 @@ public class PhoneNumberPreferenceController extends AbstractPreferenceControlle } } + @Override + public boolean isSliceable() { + return true; + } + + private CharSequence getFirstPhoneNumber() { + final List subscriptionInfoList = + mSubscriptionManager.getActiveSubscriptionInfoList(); + if (subscriptionInfoList == null) { + return mContext.getText(R.string.device_info_default); + } + + // For now, We only return first result for slice view. + return getFormattedPhoneNumber(subscriptionInfoList.get(0)); + } + private CharSequence getPhoneNumber(int simSlot) { final SubscriptionInfo subscriptionInfo = getSubscriptionInfo(simSlot); if (subscriptionInfo == null) { - return mContext.getString(R.string.device_info_default); + return mContext.getText(R.string.device_info_default); } return getFormattedPhoneNumber(subscriptionInfo); diff --git a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java index 5503ea97677..37f80b736ea 100644 --- a/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java +++ b/src/com/android/settings/deviceinfo/aboutphone/MyDeviceInfoFragment.java @@ -41,7 +41,6 @@ import com.android.settings.deviceinfo.FccEquipmentIdPreferenceController; import com.android.settings.deviceinfo.FeedbackPreferenceController; import com.android.settings.deviceinfo.IpAddressPreferenceController; import com.android.settings.deviceinfo.ManualPreferenceController; -import com.android.settings.deviceinfo.PhoneNumberPreferenceController; import com.android.settings.deviceinfo.RegulatoryInfoPreferenceController; import com.android.settings.deviceinfo.SafetyInfoPreferenceController; import com.android.settings.deviceinfo.UptimePreferenceController; @@ -110,7 +109,6 @@ public class MyDeviceInfoFragment extends DashboardFragment Lifecycle lifecycle) { final List controllers = new ArrayList<>(); controllers.add(new EmergencyInfoPreferenceController(context)); - controllers.add(new PhoneNumberPreferenceController(context)); controllers.add(new BrandedAccountPreferenceController(context)); DeviceNamePreferenceController deviceNamePreferenceController = new DeviceNamePreferenceController(context); diff --git a/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java new file mode 100644 index 00000000000..44705c59522 --- /dev/null +++ b/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProvider.java @@ -0,0 +1,56 @@ +/* + * 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.homepage.contextualcards; + +import static android.provider.SettingsSlicesContract.KEY_WIFI; + +import android.annotation.Nullable; + +import com.android.settings.homepage.deviceinfo.DataUsageSlice; +import com.android.settings.wifi.WifiSlice; + +import com.google.android.settings.intelligence.libs.contextualcards.ContextualCard; +import com.google.android.settings.intelligence.libs.contextualcards.ContextualCardProvider; + +import java.util.ArrayList; +import java.util.List; + +/** Provides dynamic card for SettingsIntelligence. */ +public class SettingsContextualCardProvider extends ContextualCardProvider { + + public static final String CARD_AUTHORITY = "com.android.settings.homepage.contextualcards"; + + @Override + @Nullable + public List getContextualCards() { + final List cards = new ArrayList<>(); + final ContextualCard wifiCard = + new ContextualCard.Builder() + .setSliceUri(WifiSlice.WIFI_URI.toString()) + .setName(KEY_WIFI) + .build(); + final ContextualCard dataUsageCard = + new ContextualCard.Builder() + .setSliceUri(DataUsageSlice.DATA_USAGE_CARD_URI.toString()) + .setName(DataUsageSlice.PATH_DATA_USAGE_CARD) + .build(); + + cards.add(wifiCard); + cards.add(dataUsageCard); + return cards; + } +} diff --git a/src/com/android/settings/network/ApnEditor.java b/src/com/android/settings/network/ApnEditor.java index 6b99e1ffeab..633fc45cb3c 100644 --- a/src/com/android/settings/network/ApnEditor.java +++ b/src/com/android/settings/network/ApnEditor.java @@ -231,9 +231,13 @@ public class ApnEditor extends SettingsPreferenceFragment final Intent intent = getIntent(); final String action = intent.getAction(); + if (TextUtils.isEmpty(action)) { + finish(); + return; + } + mSubId = intent.getIntExtra(ApnSettings.SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mReadOnlyApn = false; mReadOnlyApnTypes = null; mReadOnlyApnFields = null; diff --git a/src/com/android/settings/notification/BlockPreferenceController.java b/src/com/android/settings/notification/BlockPreferenceController.java index 9e4c4632004..bee32f511a2 100644 --- a/src/com/android/settings/notification/BlockPreferenceController.java +++ b/src/com/android/settings/notification/BlockPreferenceController.java @@ -65,6 +65,7 @@ public class BlockPreferenceController extends NotificationPreferenceController public void updateState(Preference preference) { LayoutPreference pref = (LayoutPreference) preference; + pref.setSelectable(false); SwitchBar bar = pref.findViewById(R.id.switch_bar); if (bar != null) { bar.setSwitchBarText(R.string.notification_switch_label, diff --git a/src/com/android/settings/notification/ZenDeleteRuleDialog.java b/src/com/android/settings/notification/ZenDeleteRuleDialog.java index ea582d19b88..804196edccb 100644 --- a/src/com/android/settings/notification/ZenDeleteRuleDialog.java +++ b/src/com/android/settings/notification/ZenDeleteRuleDialog.java @@ -19,15 +19,16 @@ package com.android.settings.notification; import android.app.Dialog; import android.content.DialogInterface; import android.os.Bundle; +import android.text.BidiFormatter; import android.view.View; -import androidx.appcompat.app.AlertDialog; -import androidx.fragment.app.Fragment; - import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.Fragment; + public class ZenDeleteRuleDialog extends InstrumentedDialogFragment { protected static final String TAG = "ZenDeleteRuleDialog"; private static final String EXTRA_ZEN_RULE_NAME = "zen_rule_name"; @@ -43,8 +44,9 @@ public class ZenDeleteRuleDialog extends InstrumentedDialogFragment { public static void show(Fragment parent, String ruleName, String id, PositiveClickListener listener) { + final BidiFormatter bidi = BidiFormatter.getInstance(); final Bundle args = new Bundle(); - args.putString(EXTRA_ZEN_RULE_NAME, ruleName); + args.putString(EXTRA_ZEN_RULE_NAME, bidi.unicodeWrap(ruleName)); args.putString(EXTRA_ZEN_RULE_ID, id); mPositiveClickListener = listener; diff --git a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java index b6429151b67..694625ef082 100644 --- a/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/SpecialAppAccessPreferenceControllerTest.java @@ -94,4 +94,22 @@ public class SpecialAppAccessPreferenceControllerTest { .isEqualTo(mContext.getResources().getQuantityString( R.plurals.special_access_summary, 1, 1)); } + + @Test + public void updateState_wrongExtraInfo_shouldNotIncludeInSummary() { + final ArrayList apps = new ArrayList<>(); + final ApplicationsState.AppEntry entry = mock(ApplicationsState.AppEntry.class); + entry.hasLauncherEntry = true; + entry.info = new ApplicationInfo(); + entry.extraInfo = new AppStateNotificationBridge.NotificationsSentState(); + apps.add(entry); + when(mSession.getAllApps()).thenReturn(apps); + + mController.displayPreference(mScreen); + mController.onExtraInfoUpdated(); + + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getResources().getQuantityString( + R.plurals.special_access_summary, 0, 0)); + } } diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java index 74966a2a958..e77106d2a01 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerTest.java @@ -115,6 +115,7 @@ public class AppDataUsagePreferenceControllerTest { @Test public void onPause_shouldDestroyDataLoader() { + ReflectionHelpers.setField(mController, "mStatsSession", mock(INetworkStatsSession.class)); doReturn(mLoaderManager).when(mFragment).getLoaderManager(); mController.onPause(); diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2Test.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2Test.java new file mode 100644 index 00000000000..5e9179f0fb6 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppDataUsagePreferenceControllerV2Test.java @@ -0,0 +1,144 @@ +/* + * 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.applications.appinfo; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.net.ConnectivityManager; +import android.os.Bundle; + +import com.android.settings.core.BasePreferenceController; +import com.android.settings.core.FeatureFlags; +import com.android.settings.datausage.AppDataUsageV2; +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.applications.ApplicationsState.AppEntry; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock;import android.net.INetworkStatsSession; +import android.util.FeatureFlagUtils; + +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.util.ReflectionHelpers; + +import androidx.loader.app.LoaderManager; +import androidx.preference.Preference; + +@RunWith(SettingsRobolectricTestRunner.class) +public class AppDataUsagePreferenceControllerV2Test { + + @Mock + private LoaderManager mLoaderManager; + @Mock + private AppInfoDashboardFragment mFragment; + + private Context mContext; + private AppDataUsagePreferenceControllerV2 mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application.getApplicationContext()); + mController = spy(new AppDataUsagePreferenceControllerV2(mContext, "test_key")); + mController.setParentFragment(mFragment); + FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_V2, true); + } + + @Test + public void getAvailabilityStatus_bandwidthControlEnabled_shouldReturnAvailable() { + doReturn(true).when(mController).isBandwidthControlEnabled(); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_bandwidthControlDisabled_shouldReturnDisabled() { + doReturn(false).when(mController).isBandwidthControlEnabled(); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void onResume_notAvailable_shouldNotRestartDataLoader() { + FeatureFlagUtils.setEnabled(mContext, FeatureFlags.DATA_USAGE_V2, false); + doReturn(mLoaderManager).when(mFragment).getLoaderManager(); + + mController.onResume(); + + verify(mLoaderManager, never()).restartLoader( + AppInfoDashboardFragment.LOADER_CHART_DATA, Bundle.EMPTY, mController); + } + + @Test + public void onResume_isAvailable_shouldRestartDataLoader() { + final ConnectivityManager connectivityManager = mock(ConnectivityManager.class); + when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)) + .thenReturn(connectivityManager); + when(connectivityManager.isNetworkSupported(anyInt())).thenReturn(true); + doReturn(mLoaderManager).when(mFragment).getLoaderManager(); + doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus(); + final AppEntry appEntry = mock(AppEntry.class); + appEntry.info = new ApplicationInfo(); + when(mFragment.getAppEntry()).thenReturn(appEntry); + + mController.onResume(); + + verify(mLoaderManager).restartLoader(eq(AppInfoDashboardFragment.LOADER_CHART_DATA), + nullable(Bundle.class), eq(mController)); + } + + @Test + public void onPause_shouldDestroyDataLoader() { + doReturn(BasePreferenceController.AVAILABLE).when(mController).getAvailabilityStatus(); + doReturn(mLoaderManager).when(mFragment).getLoaderManager(); + + mController.onPause(); + + verify(mLoaderManager).destroyLoader(AppInfoDashboardFragment.LOADER_CHART_DATA); + } + + @Test + public void getDetailFragmentClass_shouldReturnAppDataUsage() { + assertThat(mController.getDetailFragmentClass()).isEqualTo(AppDataUsageV2.class); + } + + @Test + public void updateState_shouldUpdatePreferenceSummary() { + final Preference preference = mock(Preference.class); + + mController.updateState(preference); + + verify(preference).setSummary(any()); + } +} diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java index d636fa468ef..e625eee5c9c 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/ExternalSourcesDetailsTest.java @@ -17,29 +17,36 @@ package com.android.settings.applications.appinfo; import static com.google.common.truth.Truth.assertThat; - import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.nullable; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import android.content.Context; +import android.content.ContextWrapper; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.os.UserHandle; import android.os.UserManager; - import com.android.settings.applications.AppStateInstallAppsBridge; import com.android.settings.applications.AppStateInstallAppsBridge.InstallAppsState; +import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.RestrictedPreferenceHelper; import com.android.settingslib.RestrictedSwitchPreference; - import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; import org.robolectric.util.ReflectionHelpers; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = {ShadowUserManager.class}) public class ExternalSourcesDetailsTest { @Mock @@ -47,6 +54,8 @@ public class ExternalSourcesDetailsTest { @Mock private RestrictedSwitchPreference mSwitchPref; @Mock + private RestrictedPreferenceHelper mHelper; + @Mock private PackageInfo mPackageInfo; private ExternalSourcesDetails mFragment; @@ -90,5 +99,128 @@ public class ExternalSourcesDetailsTest { mFragment.refreshUi(); assertThat(mFragment.refreshUi()).isTrue(); + assertThat(mSwitchPref.isDisabledByAdmin()).isFalse(); + } + + @Test + public void refreshUi_userRestrictionsUnknownSources_disablesSwitchPreference() { + // Mocks set up + final ExternalSourcesDetails fragment = new ExternalSourcesDetails(); + final ContextWrapper context = RuntimeEnvironment.application; + final UserManager userManager = (UserManager) context.getSystemService( + Context.USER_SERVICE); + final ShadowUserManager shadowUserManager = Shadow.extract(userManager); + + ReflectionHelpers.setField(fragment, "mSwitchPref", mSwitchPref); + ReflectionHelpers.setField(fragment, "mPackageInfo", mPackageInfo); + mPackageInfo.applicationInfo = new ApplicationInfo(); + ReflectionHelpers.setField(fragment, "mUserManager", userManager); + ReflectionHelpers.setField(mSwitchPref, "mHelper", mHelper); + + final AppStateInstallAppsBridge appBridge = mock(AppStateInstallAppsBridge.class); + ReflectionHelpers.setField(fragment, "mAppBridge", appBridge); + when(appBridge.createInstallAppsStateFor(nullable(String.class), anyInt())) + .thenReturn(mock(InstallAppsState.class)); + + // Test restriction set up + shadowUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()), + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); + doAnswer((answer) -> { + when(mSwitchPref.isDisabledByAdmin()).thenReturn(true); + return null; + }).when(mSwitchPref).checkRestrictionAndSetDisabled( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); + + // Code execution + assertThat(fragment.refreshUi()).isTrue(); + + // Assertions + assertThat(shadowUserManager.hasUserRestriction( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + UserHandle.of(UserHandle.myUserId()))).isTrue(); + assertThat(mSwitchPref.isDisabledByAdmin()).isTrue(); + } + + @Test + public void refreshUi_userRestrictionsUnknownSourcesGlobally_disablesSwitchPreference() { + // Mocks set up + final ExternalSourcesDetails fragment = new ExternalSourcesDetails(); + final ContextWrapper context = RuntimeEnvironment.application; + final UserManager userManager = (UserManager) context.getSystemService( + Context.USER_SERVICE); + final ShadowUserManager shadowUserManager = Shadow.extract(userManager); + + ReflectionHelpers.setField(fragment, "mSwitchPref", mSwitchPref); + ReflectionHelpers.setField(fragment, "mPackageInfo", mPackageInfo); + mPackageInfo.applicationInfo = new ApplicationInfo(); + ReflectionHelpers.setField(fragment, "mUserManager", userManager); + ReflectionHelpers.setField(mSwitchPref, "mHelper", mHelper); + + final AppStateInstallAppsBridge appBridge = mock(AppStateInstallAppsBridge.class); + ReflectionHelpers.setField(fragment, "mAppBridge", appBridge); + when(appBridge.createInstallAppsStateFor(nullable(String.class), anyInt())) + .thenReturn(mock(InstallAppsState.class)); + + // Test restriction set up + shadowUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()), + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, true); + doAnswer((answer) -> { + when(mSwitchPref.isDisabledByAdmin()).thenReturn(true); + return null; + }).when(mSwitchPref).checkRestrictionAndSetDisabled( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY); + + // Code execution + assertThat(fragment.refreshUi()).isTrue(); + + // Assertions + assertThat(shadowUserManager.hasUserRestriction( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, + UserHandle.of(UserHandle.myUserId()))).isTrue(); + assertThat(mSwitchPref.isDisabledByAdmin()).isTrue(); + } + + @Test + public void refreshUi_bothUnknownSourcesUserRestrictions_disableSwitchPreference() { + // Mocks set up + final ExternalSourcesDetails fragment = new ExternalSourcesDetails(); + final ContextWrapper context = RuntimeEnvironment.application; + final UserManager userManager = (UserManager) context.getSystemService( + Context.USER_SERVICE); + final ShadowUserManager shadowUserManager = Shadow.extract(userManager); + + ReflectionHelpers.setField(fragment, "mSwitchPref", mSwitchPref); + ReflectionHelpers.setField(fragment, "mPackageInfo", mPackageInfo); + mPackageInfo.applicationInfo = new ApplicationInfo(); + ReflectionHelpers.setField(fragment, "mUserManager", userManager); + ReflectionHelpers.setField(mSwitchPref, "mHelper", mHelper); + + final AppStateInstallAppsBridge appBridge = mock(AppStateInstallAppsBridge.class); + ReflectionHelpers.setField(fragment, "mAppBridge", appBridge); + when(appBridge.createInstallAppsStateFor(nullable(String.class), anyInt())) + .thenReturn(mock(InstallAppsState.class)); + + // Test restriction set up + shadowUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()), + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, true); + shadowUserManager.setUserRestriction(UserHandle.of(UserHandle.myUserId()), + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true); + doAnswer((answer) -> { + when(mSwitchPref.isDisabledByAdmin()).thenReturn(true); + return null; + }).when(mSwitchPref).checkRestrictionAndSetDisabled( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY); + + // Code execution + assertThat(fragment.refreshUi()).isTrue(); + + // Assertions + assertThat(shadowUserManager.hasUserRestriction( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, + UserHandle.of(UserHandle.myUserId()))).isTrue(); + assertThat(shadowUserManager.hasUserRestriction( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + UserHandle.of(UserHandle.myUserId()))).isTrue(); + assertThat(mSwitchPref.isDisabledByAdmin()).isTrue(); } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java index 4748135a461..82056a2d22b 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/PhoneNumberPreferenceControllerTest.java @@ -16,8 +16,7 @@ package com.android.settings.deviceinfo; -import static junit.framework.Assert.assertFalse; -import static junit.framework.Assert.assertTrue; +import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; @@ -27,12 +26,14 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; import org.junit.Before; @@ -41,7 +42,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; -import org.robolectric.util.ReflectionHelpers; @RunWith(SettingsRobolectricTestRunner.class) public class PhoneNumberPreferenceControllerTest { @@ -55,6 +55,8 @@ public class PhoneNumberPreferenceControllerTest { @Mock private SubscriptionInfo mSubscriptionInfo; @Mock + private SubscriptionManager mSubscriptionManager; + @Mock private PreferenceScreen mScreen; private Context mContext; @@ -63,9 +65,10 @@ public class PhoneNumberPreferenceControllerTest { @Before public void setup() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - mController = spy(new PhoneNumberPreferenceController(mContext)); - ReflectionHelpers.setField(mController, "mTelephonyManager", mTelephonyManager); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(SubscriptionManager.class)).thenReturn(mSubscriptionManager); + when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager); + mController = spy(new PhoneNumberPreferenceController(mContext, "phone_number")); final String prefKey = mController.getPreferenceKey(); when(mScreen.findPreference(prefKey)).thenReturn(mPreference); when(mScreen.getContext()).thenReturn(mContext); @@ -75,17 +78,19 @@ public class PhoneNumberPreferenceControllerTest { } @Test - public void isAvailable_shouldBeTrueIfCallCapable() { + public void getAvailabilityStatus_isVoiceCapable_shouldBeAVAILABLE() { when(mTelephonyManager.isVoiceCapable()).thenReturn(true); - assertTrue(mController.isAvailable()); + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.AVAILABLE); } @Test - public void isAvailable_shouldBeFalseIfNotCallCapable() { + public void getAvailabilityStatus_isNotVoiceCapable_shouldBeUNSUPPORTED_ON_DEVICE() { when(mTelephonyManager.isVoiceCapable()).thenReturn(false); - assertFalse(mController.isAvailable()); + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.UNSUPPORTED_ON_DEVICE); } @Test @@ -126,4 +131,19 @@ public class PhoneNumberPreferenceControllerTest { mContext.getString(R.string.status_number_sim_slot, 2 /* sim slot */)); verify(mSecondPreference).setSummary(phoneNumber); } + + @Test + public void getSummary_cannotGetActiveSubscriptionInfo_shouldShowUnknown() { + when(mSubscriptionManager.getActiveSubscriptionInfoList()).thenReturn(null); + + CharSequence primaryNumber = mController.getSummary(); + + assertThat(primaryNumber).isNotNull(); + assertThat(primaryNumber).isEqualTo(mContext.getString(R.string.device_info_default)); + } + + @Test + public void isSliceable_shouldBeTrue() { + assertThat(mController.isSliceable()).isTrue(); + } } diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java new file mode 100644 index 00000000000..80d94977607 --- /dev/null +++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/SettingsContextualCardProviderTest.java @@ -0,0 +1,64 @@ +/* + * 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.homepage.contextualcards; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.ContentResolver; +import android.content.Context; +import android.net.Uri; +import android.os.Bundle; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import com.google.android.settings.intelligence.libs.contextualcards.ContextualCard; +import com.google.android.settings.intelligence.libs.contextualcards.ContextualCardProvider; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; + +@RunWith(SettingsRobolectricTestRunner.class) +public class SettingsContextualCardProviderTest { + + private Context mContext; + private ContentResolver mResolver; + private Uri mUri; + + @Before + public void setUp() { + mContext = RuntimeEnvironment.application; + mResolver = mContext.getContentResolver(); + mUri = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsContextualCardProvider.CARD_AUTHORITY) + .build(); + } + + @Test + public void contentProviderCall_returnCorrectSize() { + final Bundle returnValue = + mResolver.call(mUri, ContextualCardProvider.METHOD_GET_CARD_LIST, "", null); + final ArrayList cards = + returnValue.getParcelableArrayList(ContextualCardProvider.BUNDLE_CARD_LIST); + assertThat(cards.size()).isEqualTo(2); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java index cc480c373e7..b6242c38ec7 100644 --- a/tests/robotests/src/com/android/settings/network/ApnEditorTest.java +++ b/tests/robotests/src/com/android/settings/network/ApnEditorTest.java @@ -19,11 +19,13 @@ package com.android.settings.network; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.content.ContentResolver; import android.content.ContentValues; @@ -450,6 +452,15 @@ public class ApnEditorTest { assertThat(ApnEditor.formatInteger("not an int")).isEqualTo("not an int"); } + @Test + public void onCreate_noAction_shouldFinishAndNoCrash() { + doNothing().when(mApnEditorUT).addPreferencesFromResource(anyInt()); + + mApnEditorUT.onCreate(null); + + verify(mApnEditorUT).finish(); + } + private void initCursor() { doReturn(2).when(mCursor).getColumnCount(); doReturn(Integer.valueOf(2)).when(mCursor).getInt(CURSOR_INTEGER_INDEX);