Snap for 11931036 from b2f88a16c9 to 24Q3-release

Change-Id: Idc4b8b4ba05bc76bfccb88d20940a2fface5aa30
This commit is contained in:
Android Build Coastguard Worker
2024-06-05 23:27:05 +00:00
33 changed files with 871 additions and 102 deletions

View File

@@ -0,0 +1,24 @@
<!--
~ Copyright (C) 2024 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path android:fillColor="@android:color/white"
android:pathData="M791,905L700,814Q651,846 595.5,863Q540,880 480,880Q397,880 324,848.5Q251,817 197,763Q143,709 111.5,636Q80,563 80,480Q80,420 97,364.5Q114,309 146,260L55,169L112,112L848,848L791,905ZM480,800Q523,800 563.5,789Q604,778 642,756L204,318Q182,356 171,396.5Q160,437 160,480Q160,613 253.5,706.5Q347,800 480,800ZM814,700L756,642Q778,604 789,563.5Q800,523 800,480Q800,347 706.5,253.5Q613,160 480,160Q437,160 396.5,171Q356,182 318,204L260,146Q309,114 364.5,97Q420,80 480,80Q563,80 636,111.5Q709,143 763,197Q817,251 848.5,324Q880,397 880,480Q880,540 863,595.5Q846,651 814,700ZM537,423L537,423Q537,423 537,423Q537,423 537,423Q537,423 537,423Q537,423 537,423Q537,423 537,423Q537,423 537,423ZM423,537Q423,537 423,537Q423,537 423,537L423,537Q423,537 423,537Q423,537 423,537Q423,537 423,537Q423,537 423,537Z"/>
</vector>

View File

@@ -20,6 +20,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="true"
android:orientation="vertical">
<ImageView
@@ -54,7 +55,8 @@
<ImageView
android:id="@+id/bt_battery_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
android:layout_height="wrap_content"
android:contentDescription="@string/bluetooth_header_battery_content_description" />
<TextView
android:id="@+id/bt_battery_summary"
style="@style/TextAppearance.EntityHeaderSummary"

View File

@@ -81,6 +81,23 @@
android:layout_toRightOf="@+id/appsIcon"
android:text="@string/private_space_install_apps_text"/>
</RelativeLayout>
<TextView
style="@style/PrivateSpaceSetupSubHeaderStyle"
android:text="@string/private_space_keep_in_mind_text"/>
<RelativeLayout
style="@style/PrivateSpaceSetupBulletPointLayoutStyle"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/eduIcon"
style="@style/PrivateSpaceBulletPointIconStyle"
android:contentDescription="@null"
android:src="@drawable/ic_private_space_edu_icon" />
<TextView
style="@style/PrivateSpaceBulletPointTextFontStyle"
android:layout_toRightOf="@+id/eduIcon"
android:text="@string/private_space_apps_stopped_text"/>
</RelativeLayout>
<Space
android:layout_width="wrap_content"
android:layout_height="16dp"/>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -732,7 +732,7 @@
<!-- Button text to cancel enrollment from the introduction [CHAR LIMIT=22] -->
<string name="security_settings_face_enroll_introduction_cancel">Cancel</string>
<!-- Button text to cancel enrollment [CHAR LIMIT=30] -->
<string name="security_settings_face_enroll_introduction_no_thanks">No thanks</string>
<string name="security_settings_face_enroll_introduction_no_thanks">Not now</string>
<!-- Button text to start enrollment [CHAR LIMIT=30] -->
<string name="security_settings_face_enroll_introduction_agree">I agree</string>
<!-- Button text to scroll to the end of a scrollview. [CHAR LIMIT=30] -->
@@ -861,7 +861,7 @@
<!-- Button text to cancel enrollment from the introduction [CHAR LIMIT=22] -->
<string name="security_settings_fingerprint_enroll_introduction_cancel">Cancel</string>
<!-- Button text to cancel enrollment [CHAR LIMIT=30] -->
<string name="security_settings_fingerprint_enroll_introduction_no_thanks">No thanks</string>
<string name="security_settings_fingerprint_enroll_introduction_no_thanks">Not now</string>
<!-- Button text to agree the consent and continue to the next screen from the introduction [CHAR LIMIT=22] -->
<string name="security_settings_fingerprint_enroll_introduction_agree">I agree</string>
<!-- Title of dialog shown when the user tries to skip setting up fingerprint after adding lock screen during initial setup. [CHAR LIMIT=30] -->
@@ -1345,15 +1345,21 @@
<!-- Summary for the private space setup education screen. [CHAR LIMIT=NONE] -->
<string name="private_space_hide_apps_summary">Hide or lock private apps in a separate space. Use a dedicated Google Account for extra security.</string>
<!-- Text shown in private space setup screen which explains how the private space works [CHAR LIMIT=50] -->
<string name="private_space_setup_sub_header">Set up your private space</string>
<string name="private_space_setup_sub_header">How it works</string>
<!-- Text shown in private space setup screen which explains private space can be accessed from bottom of all apps list. [CHAR LIMIT=NONE] -->
<string name="private_space_separate_account_text"><b>Choose a Google Account for your space</b>\nUsing a dedicated account helps to stop synced files, photos, and emails appearing outside your space</string>
<string name="private_space_separate_account_text"><b>Create a Google Account for your space</b>\nIf you use a dedicated account, it helps to stop synced files, photos, and emails appearing outside your space</string>
<!-- Text shown in private space setup screen which explains private space apps are protected by a lock. [CHAR LIMIT=NONE] -->
<string name="private_space_protected_lock_text"><b>Set a lock</b>\nLock your space to stop other people opening it</string>
<!-- Text shown in private space setup screen which explains notifications from private space apps will not be shown when private space is locked. [CHAR LIMIT=NONE] -->
<string name="private_space_install_apps_text"><b>Install apps</b>\nYour private space has its own Play Store so you can install apps easily.</string>
<string name="private_space_install_apps_text"><b>Install apps</b>\nInstall apps that you want to keep private in your space</string>
<!-- Category name "Keep in mind" [CHAR_LIMIT=40] -->
<string name="private_space_keep_in_mind_text">Keep in mind</string>
<!-- Text shown in private space setup screen which explains that apps in private space are stopped when private space is locked. [CHAR LIMIT=NONE] -->
<string name="private_space_apps_stopped_text"><b>Apps stop when you lock your space</b>\nWhen you lock your space, apps in your space are stopped and you won\u2019t receive notifications from them</string>
<!-- This is info text to help explain in private space setup screen that the permissions granted to private space apps will not be shown in settings when private space is locked. [CHAR LIMIT=NONE] -->
<string name="private_space_apps_permission_text">Apps in your private space won\'t appear in permission manager, privacy dashboard, and other settings when your private space is locked.\n\nYour private space can\'t be restored to a new device. You\'ll need to set up another private space if you want to use it on another device.\n\nAnyone that connects your device to a computer or installs malicious apps on your device may be able to access your private space.</string>
<string name="private_space_apps_permission_text">Apps in your private space won\'t appear in permission manager, privacy dashboard, and other settings when your private space is locked.\n\nYour private space can\'t be moved to a new device. You\'ll need to set up another private space if you want to use it on another device.\n\nAnyone that connects your device to a computer or installs harmful apps on your device may be able to access your private space.</string>
<!-- This is footer text in private space settings page to help explain that when private space is locked the apps are stopped, the permissions granted to private space apps will not be shown in settings. [CHAR LIMIT=NONE] -->
<string name="private_space_settings_footer_text">When you lock your space, apps in your private space are stopped and you won\u2019t receive notifications from them.\n\nApps in your private space won\'t appear in permission manager, privacy dashboard, and other settings when private space is locked.\n\nYour private space can\'t be restored to a new device. You\u2019ll need to set up another space if you want to use it on another device.\n\nAnyone that connects your device to a computer or installs malicious apps on your device may be able to access your private space.</string>
<!-- Private space footer link content description [CHAR LIMIT=40] -->
<string name="private_space_learn_more_text">Learn more about private space</string>
<string name="private_space_learn_more_url" translatable="false">https://support.google.com/android?p=private_space</string>
@@ -2360,6 +2366,8 @@
<!-- Wifi Network Details -->
<!-- Wifi details title-->
<string name="wifi_details_title">Network details</string>
<!-- WEP network less secure warning title -->
<string name="wep_network_less_secure_warning_title">This network uses an older security protocol called WEP, which is less secure</string>
<!-- Wifi details preference title to display router IP subnet mask -->
<string name="wifi_details_subnet_mask">Subnet mask</string>
<!-- Server name title-->
@@ -8720,7 +8728,7 @@
<string name="notif_listener_more_settings">More settings</string>
<string name="notif_listener_more_settings_desc">More settings are available inside this app</string>
<!-- Title for Polite Notifications setting [CHAR LIMIT=30]-->
<!-- Title for Polite Notifications setting [CHAR LIMIT=45]-->
<string name="notification_polite_title">Cooldown</string>
<string name="notification_polite_main_control_title">Use Cooldown</string>
<string name="notification_polite_description">When you get many notifications within a short time span, your device will minimize sound interruptions and pop-ups on the screen. Calls, alarms, and priority conversations will still alert as notmal, and all delivered notifications are easy to find in the Shade.</string>
@@ -12052,6 +12060,8 @@
<string name="bluetooth_right_name">Right</string>
<!-- Title for middle bluetooth device. [CHAR LIMIT=NONE] -->
<string name="bluetooth_middle_name">Case</string>
<!-- Content description for battery icon in bluetooth header. [CHAR LIMIT=NONE] -->
<string name="bluetooth_header_battery_content_description">Battery</string>
<!-- Default title for the settings panel [CHAR LIMIT=NONE] -->
<string name="settings_panel_title">Settings Panel</string>

View File

@@ -77,7 +77,7 @@
<com.android.settingslib.widget.FooterPreference
android:key="private_space_footer"
android:title="@string/private_space_apps_permission_text"
android:title="@string/private_space_settings_footer_text"
android:selectable="false"
settings:searchable="false"
settings:controller="com.android.settings.privatespace.PrivateSpaceFooterPreferenceController"/>

View File

@@ -32,14 +32,12 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.content.pm.UserInfo;
import android.os.Flags;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
import com.android.settings.Settings.CreateShortcutActivity;
import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.homepage.DeepLinkHomepageActivity;
import com.android.settings.search.SearchStateReceiver;
@@ -49,7 +47,7 @@ import java.util.ArrayList;
import java.util.List;
/**
* Listens to {@link Intent.ACTION_PRE_BOOT_COMPLETED} and {@link Intent.ACTION_USER_INITIALIZED}
* Listens to {@link Intent.ACTION_PRE_BOOT_COMPLETED} and {@link Intent.ACTION_USER_INITIALIZE}
* performs setup steps for a managed profile (disables the launcher icon of the Settings app,
* adds cross-profile intent filters for the appropriate Settings activities), disables the
* webview setting for non-admin users, updates the intent flags for any existing shortcuts and
@@ -68,7 +66,6 @@ public class SettingsInitialize extends BroadcastReceiver {
final PackageManager pm = context.getPackageManager();
managedProfileSetup(context, pm, broadcast, userInfo);
cloneProfileSetup(context, pm, userInfo);
privateProfileSetup(context, pm, userInfo);
webviewSettingSetup(context, pm, userInfo);
ThreadUtils.postOnBackgroundThread(() -> refreshExistingShortcuts(context));
enableTwoPaneDeepLinkActivityIfNecessary(pm, context);
@@ -106,7 +103,7 @@ public class SettingsInitialize extends BroadcastReceiver {
}
}
disableComponentsToHideSettings(context, pm);
Utils.disableComponentsToHideSettings(context, pm);
}
private void cloneProfileSetup(Context context, PackageManager pm, UserInfo userInfo) {
@@ -114,31 +111,7 @@ public class SettingsInitialize extends BroadcastReceiver {
return;
}
disableComponentsToHideSettings(context, pm);
}
private void privateProfileSetup(Context context, PackageManager pm, UserInfo userInfo) {
if (Flags.allowPrivateProfile()
&& android.multiuser.Flags.enablePrivateSpaceFeatures()) {
if (userInfo == null || !userInfo.isPrivateProfile()) {
return;
}
disableComponentsToHideSettings(context, pm);
}
}
private void disableComponentsToHideSettings(Context context, PackageManager pm) {
// Disable settings app launcher icon
disableComponent(pm, new ComponentName(context, Settings.class));
//Disable Shortcut picker
disableComponent(pm, new ComponentName(context, CreateShortcutActivity.class));
}
private void disableComponent(PackageManager pm, ComponentName componentName) {
pm.setComponentEnabledSetting(componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
Utils.disableComponentsToHideSettings(context, pm);
}
// Disable WebView Setting if the current user is not an admin

View File

@@ -1464,4 +1464,22 @@ public final class Utils extends com.android.settingslib.Utils {
}
};
}
/**
* Disables the launcher icon and shortcut picker component for the Settings app corresponding
* to the context user.
*/
public static void disableComponentsToHideSettings(@NonNull Context context,
@NonNull PackageManager pm) {
// Disable settings app launcher icon
disableComponent(pm, new ComponentName(context, Settings.class));
//Disable Shortcut picker
disableComponent(pm, new ComponentName(context, Settings.CreateShortcutActivity.class));
}
private static void disableComponent(PackageManager pm, ComponentName componentName) {
pm.setComponentEnabledSetting(componentName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
}

View File

@@ -33,6 +33,10 @@ import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.collection.ArraySet;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceClickListener;
import androidx.preference.PreferenceFragmentCompat;
@@ -46,6 +50,8 @@ import com.android.settings.utils.LocalClassLoaderContextThemeWrapper;
import com.android.settingslib.accounts.AuthenticatorHelper;
import com.android.settingslib.core.instrumentation.Instrumentable;
import java.util.Set;
/**
* Class to load the preference screen to be added to the settings page for the specific account
* type as specified in the account-authenticator.
@@ -83,6 +89,7 @@ public class AccountTypePreferenceLoader {
try {
desc = mAuthenticatorHelper.getAccountTypeDescription(accountType);
if (desc != null && desc.accountPreferencesId != 0) {
Set<String> fragmentAllowList = generateFragmentAllowlist(parent);
// Load the context of the target package, then apply the
// base Settings theme (no references to local resources)
// and create a context theme wrapper so that we get the
@@ -99,6 +106,12 @@ public class AccountTypePreferenceLoader {
themedCtx.getTheme().setTo(baseTheme);
prefs = mFragment.getPreferenceManager().inflateFromResource(themedCtx,
desc.accountPreferencesId, parent);
// Ignore Fragments provided dynamically, as these are coming from external
// applications which must not have access to internal Settings' fragments.
// These preferences are rendered into Settings, so they also won't have access
// to their own Fragments, meaning there is no acceptable usage of
// android:fragment here.
filterBlockedFragments(prefs, fragmentAllowList);
}
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Couldn't load preferences.xml file from " + desc.packageName);
@@ -186,6 +199,48 @@ public class AccountTypePreferenceLoader {
}
}
// Build allowlist from existing Fragments in PreferenceGroup
@VisibleForTesting
Set<String> generateFragmentAllowlist(@Nullable PreferenceGroup prefs) {
Set<String> fragmentAllowList = new ArraySet<>();
if (prefs == null) {
return fragmentAllowList;
}
for (int i = 0; i < prefs.getPreferenceCount(); i++) {
Preference pref = prefs.getPreference(i);
if (pref instanceof PreferenceGroup) {
fragmentAllowList.addAll(generateFragmentAllowlist((PreferenceGroup) pref));
}
String fragmentName = pref.getFragment();
if (!TextUtils.isEmpty(fragmentName)) {
fragmentAllowList.add(fragmentName);
}
}
return fragmentAllowList;
}
// Block clicks on any Preference with android:fragment that is not contained in the allowlist
@VisibleForTesting
void filterBlockedFragments(@Nullable PreferenceGroup prefs,
@NonNull Set<String> allowedFragments) {
if (prefs == null) {
return;
}
for (int i = 0; i < prefs.getPreferenceCount(); i++) {
Preference pref = prefs.getPreference(i);
if (pref instanceof PreferenceGroup) {
filterBlockedFragments((PreferenceGroup) pref, allowedFragments);
}
String fragmentName = pref.getFragment();
if (fragmentName != null && !allowedFragments.contains(fragmentName)) {
pref.setOnPreferenceClickListener(preference -> true);
}
}
}
/**
* Determines if the supplied Intent is safe. A safe intent is one that is
* will launch a exported=true activity or owned by the same uid as the

View File

@@ -33,6 +33,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.settings.R;
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action;
import com.android.settings.fuelgauge.batteryusage.AppOptModeSharedPreferencesUtils;
import com.android.settingslib.datastore.DataChangeReason;
import com.android.settingslib.fuelgauge.PowerAllowlistBackend;
@@ -138,7 +139,8 @@ public class BatteryOptimizeUtils {
/** Resets optimization mode for all applications. */
public static void resetAppOptimizationMode(
Context context, IPackageManager ipm, AppOpsManager aom) {
resetAppOptimizationMode(
AppOptModeSharedPreferencesUtils.clearAll(context);
resetAppOptimizationModeInternal(
context,
ipm,
aom,
@@ -219,7 +221,7 @@ public class BatteryOptimizeUtils {
}
@VisibleForTesting
static void resetAppOptimizationMode(
static void resetAppOptimizationModeInternal(
Context context,
IPackageManager ipm,
AppOpsManager aom,

View File

@@ -41,6 +41,13 @@ object AppOptModeSharedPreferencesUtils {
fun getAllEvents(context: Context): List<AppOptimizationModeEvent> =
synchronized(appOptimizationModeLock) { getAppOptModeEventsMap(context).values.toList() }
/** Removes all app optimization mode events. */
@JvmStatic
fun clearAll(context: Context) =
synchronized(appOptimizationModeLock) {
getSharedPreferences(context).edit().clear().apply()
}
/** Updates the app optimization mode event data. */
@JvmStatic
fun updateAppOptModeExpiration(

View File

@@ -58,6 +58,7 @@ public class KeyboardSettingsPreferenceController extends BasePreferenceControll
intent.putExtra(
Settings.EXTRA_INPUT_DEVICE_IDENTIFIER,
hardKeyboardDeviceInfo.mDeviceIdentifier);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
mContext.startActivity(intent);
break;
}

View File

@@ -99,8 +99,6 @@ import java.util.Optional;
/**
* UI for Mobile network and Wi-Fi network settings.
*
* TODO(b/167474581): Define the intent android.settings.NETWORK_PROVIDER_SETTINGS in Settings.java.
*/
@SearchIndexable
public class NetworkProviderSettings extends RestrictedSettingsFragment
@@ -108,9 +106,6 @@ public class NetworkProviderSettings extends RestrictedSettingsFragment
WifiDialog2.WifiDialog2Listener, DialogInterface.OnDismissListener,
AirplaneModeEnabler.OnAirplaneModeChangedListener, InternetUpdater.InternetChangeListener {
public static final String ACTION_NETWORK_PROVIDER_SETTINGS =
"android.settings.NETWORK_PROVIDER_SETTINGS";
private static final String TAG = "NetworkProviderSettings";
// IDs of context menu
static final int MENU_ID_CONNECT = Menu.FIRST + 1;

View File

@@ -56,6 +56,8 @@ import com.google.common.collect.ImmutableList;
import kotlin.Unit;
import kotlinx.coroutines.Job;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -96,6 +98,8 @@ public class NetworkSelectSettings extends DashboardFragment {
private AtomicBoolean mShouldFilterOutSatellitePlmn = new AtomicBoolean();
private NetworkScanRepository mNetworkScanRepository;
@Nullable
private Job mNetworkScanJob = null;
private NetworkSelectRepository mNetworkSelectRepository;
@@ -213,13 +217,14 @@ public class NetworkSelectSettings extends DashboardFragment {
private void launchNetworkScan() {
setProgressBarVisible(true);
mNetworkScanRepository.launchNetworkScan(getViewLifecycleOwner(), (networkScanResult) -> {
if (isPreferenceScreenEnabled()) {
scanResultHandler(networkScanResult);
}
mNetworkScanJob = mNetworkScanRepository.launchNetworkScan(getViewLifecycleOwner(),
(networkScanResult) -> {
if (isPreferenceScreenEnabled()) {
scanResultHandler(networkScanResult);
}
return Unit.INSTANCE;
});
return Unit.INSTANCE;
});
}
/**
@@ -245,6 +250,12 @@ public class NetworkSelectSettings extends DashboardFragment {
return false;
}
// Need stop network scan before manual select network.
if (mNetworkScanJob != null) {
mNetworkScanJob.cancel(null);
mNetworkScanJob = null;
}
// Refresh the last selected item in case users reselect network.
clearPreferenceSummary();
if (mSelectedPreference != null) {

View File

@@ -52,9 +52,8 @@ class NetworkScanRepository(private val context: Context, subId: Int) {
private val telephonyManager = context.telephonyManager(subId)
/** TODO: Move this to UI layer, when UI layer migrated to Kotlin. */
fun launchNetworkScan(lifecycleOwner: LifecycleOwner, onResult: (NetworkScanResult) -> Unit) {
fun launchNetworkScan(lifecycleOwner: LifecycleOwner, onResult: (NetworkScanResult) -> Unit) =
networkScanFlow().collectLatestWithLifecycle(lifecycleOwner, action = onResult)
}
data class CellInfoScanKey(
val title: String?,
@@ -101,7 +100,10 @@ class NetworkScanRepository(private val context: Context, subId: Int) {
callback,
)
awaitClose { networkScan.stopScan() }
awaitClose {
networkScan.stopScan()
Log.d(TAG, "network scan stopped")
}
}.conflate().onEach { Log.d(TAG, "networkScanFlow: $it") }.flowOn(Dispatchers.Default)
/** Create network scan for allowed network types. */

View File

@@ -80,8 +80,10 @@ public class BubblePreference extends Preference implements RadioGroup.OnChecked
}
public void setSelectedVisibility(boolean visible) {
mSelectedVisible = visible;
notifyChanged();
if (mSelectedVisible != visible) {
mSelectedVisible = visible;
notifyChanged();
}
}
@Override

View File

@@ -31,6 +31,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Flags;
import android.os.UserHandle;
@@ -44,6 +45,7 @@ import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.annotations.GuardedBy;
import com.android.settings.Utils;
import java.util.List;
@@ -129,6 +131,7 @@ public class PrivateSpaceMaintainer {
resetPrivateSpaceSettings();
setUserSetupComplete();
setSkipFirstUseHints();
disableComponentsToHidePrivateSpaceSettings();
}
return true;
}
@@ -356,6 +359,24 @@ public class PrivateSpaceMaintainer {
1, mUserHandle.getIdentifier());
}
/**
* Disables the launcher icon and shortcut picker component for the Settings app instance
* inside the private space
*/
@GuardedBy("this")
private void disableComponentsToHidePrivateSpaceSettings() {
if (mUserHandle == null) {
Log.e(TAG, "User handle null while hiding settings icon");
return;
}
Context privateSpaceUserContext = mContext.createContextAsUser(mUserHandle, /* flags */ 0);
PackageManager packageManager = privateSpaceUserContext.getPackageManager();
Log.d(TAG, "Hiding settings app launcher icon for " + mUserHandle);
Utils.disableComponentsToHideSettings(privateSpaceUserContext, packageManager);
}
/**
* Sets the SKIP_FIRST_USE_HINTS for private profile so that the first launch of an app in
* private space will not display introductory hints.

View File

@@ -22,7 +22,6 @@ import android.app.AppOpsManager
import android.app.AppOpsManager.MODE_DEFAULT
import android.content.Context
import android.content.pm.ApplicationInfo
import android.os.Process
import android.os.UserManager
import androidx.compose.runtime.Composable
import com.android.settings.R
@@ -92,10 +91,8 @@ class InstallUnknownAppsListModel(private val context: Context) :
private fun isChangeable(
record: InstallUnknownAppsRecord,
potentialPackageNames: Set<String>,
) =
record.app.uid != Process.SYSTEM_UID && record.app.uid != Process.ROOT_UID &&
(record.appOpsController.getMode() != MODE_DEFAULT ||
record.app.packageName in potentialPackageNames)
) = record.appOpsController.getMode() != MODE_DEFAULT ||
record.app.packageName in potentialPackageNames
private fun getPotentialPackageNames(userId: Int): Set<String> =
AppGlobals.getPackageManager()

View File

@@ -22,6 +22,7 @@ import static android.net.wifi.SoftApConfiguration.BAND_5GHZ;
import static android.net.wifi.SoftApConfiguration.BAND_6GHZ;
import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_OPEN;
import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE;
import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION;
import static android.net.wifi.WifiAvailableChannel.OP_MODE_SAP;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
@@ -343,16 +344,23 @@ public class WifiHotspotRepository {
log("setSpeedType(), setPassphrase(SECURITY_TYPE_WPA3_SAE)");
configBuilder.setPassphrase(generatePassword(config), SECURITY_TYPE_WPA3_SAE);
}
} else if (speedType == SPEED_5GHZ) {
log("setSpeedType(), setBand(BAND_2GHZ_5GHZ)");
configBuilder.setBand(BAND_2GHZ_5GHZ);
} else if (mIsDualBand) {
log("setSpeedType(), setBands(BAND_2GHZ + BAND_2GHZ_5GHZ)");
int[] bands = {BAND_2GHZ, BAND_2GHZ_5GHZ};
configBuilder.setBands(bands);
} else {
log("setSpeedType(), setBand(BAND_2GHZ)");
configBuilder.setBand(BAND_2GHZ);
if (speedType == SPEED_5GHZ) {
log("setSpeedType(), setBand(BAND_2GHZ_5GHZ)");
configBuilder.setBand(BAND_2GHZ_5GHZ);
} else if (mIsDualBand) {
log("setSpeedType(), setBands(BAND_2GHZ + BAND_2GHZ_5GHZ)");
int[] bands = {BAND_2GHZ, BAND_2GHZ_5GHZ};
configBuilder.setBands(bands);
} else {
log("setSpeedType(), setBand(BAND_2GHZ)");
configBuilder.setBand(BAND_2GHZ);
}
// Set the security type back to WPA2/WPA3 if we're moving from 6GHz to something else.
if ((config.getBand() & BAND_6GHZ) != 0) {
configBuilder.setPassphrase(
generatePassword(config), SECURITY_TYPE_WPA3_SAE_TRANSITION);
}
}
setSoftApConfiguration(configBuilder.build());
}

View File

@@ -0,0 +1,62 @@
// Copyright (C) 2024 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 {
default_applicable_licenses: ["packages_apps_Settings_license"],
default_team: "trendy_team_android_kernel",
}
android_test_helper_app {
name: "test_16kb_app",
srcs: ["test_16kb_app/src/**/*.java"],
manifest: "test_16kb_app/test_16kb_app.xml",
static_libs: [
"androidx.test.ext.junit",
"androidx.test.rules",
"androidx.test.uiautomator_uiautomator",
"platform-test-annotations",
"settings-helper",
"sysui-helper",
"truth",
"flag-junit",
],
platform_apis: true,
certificate: "platform",
test_suites: ["general-tests"],
libs: [
"android.test.runner",
"android.test.base",
],
}
java_test_host {
name: "Enable16KbTest",
// Include all test java files
srcs: ["src/**/*.java"],
static_libs: [
"junit",
"platform-test-annotations",
"truth",
],
libs: [
"tradefed",
"compatibility-host-util",
"compatibility-tradefed",
],
data: [
":test_16kb_app",
],
test_suites: ["general-tests"],
test_config: "AndroidTest.xml",
}

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2024 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.
-->
<configuration description="Runs 16K developer option test.">
<option name="test-suite-tag" value="apct"/>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="test_16kb_app.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
<option name="force-root" value="false" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="Enable16KbTest.jar" />
</test>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<!-- Unlock screen -->
<option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
<!-- Dismiss keyguard, in case it's set as "Swipe to unlock" -->
<option name="run-command" value="wm dismiss-keyguard" />
<!-- Collapse notifications -->
<option name="run-command" value="cmd statusbar collapse" />
<!-- dismiss all system dialogs before launch test -->
<option name="run-command" value="am broadcast -a android.intent.action.CLOSE_SYSTEM_DIALOGS" />
</target_preparer>
</configuration>

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2024 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.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import android.platform.test.annotations.AppModeFull;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.testtype.junit4.DeviceTestRunOptions;
import com.android.tradefed.util.RunUtil;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.BufferedReader;
import java.io.StringReader;
@RunWith(DeviceJUnit4ClassRunner.class)
public class Enable16KbTest extends BaseHostJUnit4Test {
private static final String TEST_APP_NAME = "test_16kb_app.apk";
private static final String APP_PACKAGE = "com.android.settings.development.test";
private static final String TEST_NAME = "Enable16KbDeviceTest";
private static final String SWITCH_TO_EXT4 = "enable16k_switchToExt4";
private static final String SWITCH_TO_16KB = "enable16k_switchTo16Kb";
private static final String SWITCH_TO_4KB = "enable16k_switchTo4Kb";
private static final String DISABLE_DEV_OPTION = "enable16k_disableDeveloperOption";
@Test
@AppModeFull
public void enable16KbToggle() throws Exception {
assertTrue(isPackageInstalled(APP_PACKAGE));
// Check if developer option is enabled otherwise exit
getDevice().enableAdbRoot();
String result = getDevice().getProperty("ro.product.build.16k_page.enabled");
assumeTrue("true".equals(result));
// This test can be run on OEM unlocked device only as unlocking bootloader requires
// manual intervention.
result = getDevice().getProperty("ro.boot.flash.locked");
assumeTrue("0".equals(result));
getDevice().executeShellCommand("am start -a com.android.setupwizard.FOUR_CORNER_EXIT");
// Enables developer option and switch to ext4
runTestAndWait(SWITCH_TO_EXT4);
getDevice().enableAdbRoot();
getDevice().executeShellCommand("am start -a com.android.setupwizard.FOUR_CORNER_EXIT");
assertTrue(verifyExt4());
// Device will wiped. need to install test package again.
installTestApp();
// Enable developer option and switch to 16kb kernel and Check page size
runTestAndWait(SWITCH_TO_16KB);
result = getDevice().executeShellCommand("getconf PAGE_SIZE");
assertEquals("16384", result.strip());
// switch back to 4kb kernel and check page size
runTestAndWait(SWITCH_TO_4KB);
result = getDevice().executeShellCommand("getconf PAGE_SIZE");
assertEquals("4096", result.strip());
// Verify that developer options can't be turned off
runDeviceTests(APP_PACKAGE, APP_PACKAGE + "." + TEST_NAME, DISABLE_DEV_OPTION);
}
private void installTestApp() throws Exception {
DeviceTestRunOptions options = new DeviceTestRunOptions(null /* unused */);
options.setApkFileName(TEST_APP_NAME);
options.setInstallArgs("-r");
installPackage(options);
assertTrue(isPackageInstalled(APP_PACKAGE));
}
private void runTestAndWait(String testMethodName) throws Exception {
runDeviceTests(APP_PACKAGE, APP_PACKAGE + "." + TEST_NAME, testMethodName);
// Device is either formatting or applying update. It usually takes 3 minutes to boot.
RunUtil.getDefault().sleep(180000);
// Wait for 2 mins device to be online againg
getDevice().waitForDeviceOnline(120000);
}
private boolean verifyExt4() throws Exception {
String result = getDevice().executeShellCommand("cat /proc/mounts");
BufferedReader br = new BufferedReader(new StringReader(result));
String line;
while ((line = br.readLine()) != null) {
final String[] fields = line.split(" ");
final String partition = fields[1];
final String fsType = fields[2];
if (partition.equals("/data") && fsType.equals("ext4")) {
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,170 @@
/*
* Copyright (C) 2024 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.development.test;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.os.RemoteException;
import android.provider.Settings;
import android.system.helpers.SettingsHelper;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.Until;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
public class Enable16KbDeviceTest {
private static final long TIMEOUT = 2000;
private static final String ENABLE_16K_TOGGLE = "Boot with 16KB page size";
private static final String BUILD_NUMBER = "Build number";
private static final String USE_DEVELOPER_OPTIONS = "Use developer options";
private static final String EXT4_CONFIRMATION = "Erase all data";
private static final String EXT4_TITLE = "Reformat device to ext4? (required for 16KB mode)";
private static final String TOGGLE_16K_TITLE = "Switch from 4KB mode to 16KB mode";
private static final String TOGGLE_4K_TITLE = "Switch from 16KB mode to 4KB mode";
private static final String ANDROID_WIDGET_SCROLLVIEW = "android.widget.ScrollView";
private static final String OKAY = "OK";
private static final String NOTIFICATION_TITLE_4K = "Using 4KB page-agnostic mode";
private static final String NOTIFICATION_TITLE_16K = "Using 16KB page-agnostic mode";
private Context mContext;
private UiDevice mDevice;
private SettingsHelper mHelper;
@Before
public void setUp() throws Exception {
mContext = getInstrumentation().getTargetContext();
mDevice = UiDevice.getInstance(getInstrumentation());
mHelper = SettingsHelper.getInstance();
try {
mDevice.setOrientationNatural();
} catch (RemoteException e) {
throw new RuntimeException("failed to freeze device orientation", e);
}
mDevice.executeShellCommand("input keyevent KEYCODE_WAKEUP");
mDevice.executeShellCommand("wm dismiss-keyguard");
}
private void unlockDeveloperOptions() throws Exception {
SettingsHelper.launchSettingsPage(mContext, Settings.ACTION_DEVICE_INFO_SETTINGS);
// Click 7 times on build number to unlock the dev options
for (int i = 0; i < 7; i++) {
mHelper.clickSetting(BUILD_NUMBER);
}
}
@Test
public void enable16k_switchToExt4() throws Exception {
unlockDeveloperOptions();
SettingsHelper.launchSettingsPage(
mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
clickOnObject(By.text(ENABLE_16K_TOGGLE));
// Verify that ext4 toggle is visible
verifyTextOnScreen(EXT4_TITLE);
mDevice.wait(Until.findObject(By.text(EXT4_CONFIRMATION)), TIMEOUT).click();
}
@Test
public void enable16k_switchTo16Kb() throws Exception {
// Device will be in 4kb mode
openPersistentNotification(NOTIFICATION_TITLE_4K);
unlockDeveloperOptions();
SettingsHelper.launchSettingsPage(
mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
clickOnObject(By.text(ENABLE_16K_TOGGLE));
// Verify that text is displayed to switch to 16kb
verifyTextOnScreen(TOGGLE_16K_TITLE);
mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
}
@Test
public void enable16k_switchTo4Kb() throws Exception {
// Device will be in 16kb mode
openPersistentNotification(NOTIFICATION_TITLE_16K);
SettingsHelper.launchSettingsPage(
mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
clickOnObject(By.text(ENABLE_16K_TOGGLE));
// Verify that text is displayed to switch to 4kb
verifyTextOnScreen(TOGGLE_4K_TITLE);
mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
}
private void clickOnObject(BySelector target) {
mDevice.waitForWindowUpdate(null, TIMEOUT);
UiObject2 scrollView =
mDevice.wait(
Until.findObject(By.scrollable(true).clazz(ANDROID_WIDGET_SCROLLVIEW)),
TIMEOUT);
UiObject2 targetObject = scrollTo(scrollView, target, Direction.DOWN);
assertTrue(targetObject != null);
targetObject.click();
}
private UiObject2 scrollTo(UiObject2 scrollable, BySelector target, Direction direction) {
while (!mDevice.hasObject(target) && scrollable.scroll(direction, 1.0f)) {
// continue
}
if (!mDevice.hasObject(target)) {
scrollable.scroll(direction, 1.0f);
}
return mDevice.findObject(target);
}
private void verifyTextOnScreen(String displayedText) {
UiObject2 targetObject = mDevice.wait(Until.findObject(By.text(displayedText)), TIMEOUT);
assertTrue(targetObject != null);
}
private void openPersistentNotification(String title) {
mDevice.openNotification();
verifyTextOnScreen(title);
mDevice.wait(Until.findObject(By.text(title)), TIMEOUT).click();
mDevice.waitForWindowUpdate(null, TIMEOUT);
verifyTextOnScreen(title);
mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
mDevice.waitForWindowUpdate(null, TIMEOUT);
}
@Test
public void enable16k_disableDeveloperOption() throws Exception {
// Device will be in 4KB mode when this test will be run
SettingsHelper.launchSettingsPage(
mContext, Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
mDevice.wait(Until.findObject(By.text(USE_DEVELOPER_OPTIONS)), TIMEOUT).click();
verifyTextOnScreen(NOTIFICATION_TITLE_4K);
mDevice.wait(Until.findObject(By.text(OKAY)), TIMEOUT).click();
}
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2024 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.settings.development.test"
android:sharedUserId="android.uid.systemui">
<application>
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation
android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.settings.development.test"/>
</manifest>

View File

@@ -12,8 +12,8 @@ package {
android_app {
name: "SettingsRoboTestStub",
defaults: [
"SettingsLibDefaults",
"SettingsLib-search-defaults",
"SettingsLibDefaults",
],
platform_apis: true,
certificate: "platform",
@@ -23,18 +23,18 @@ android_app {
static_libs: [
"Settings-core",
"androidx.fragment_fragment-testing",
"frameworks-base-testutils",
"androidx.fragment_fragment",
"androidx.fragment_fragment-testing",
"androidx.lifecycle_lifecycle-runtime-testing",
"frameworks-base-testutils",
"kotlinx_coroutines_test",
],
aaptflags: ["--extra-packages com.android.settings"],
libs: [
"telephony-common",
"ims-common",
"telephony-common",
],
uses_libs: ["org.apache.http.legacy"],
optional_uses_libs: [
@@ -47,36 +47,64 @@ android_app {
android_robolectric_test {
name: "SettingsRoboTests",
srcs: [
"src/**/*.java",
"src/**/*.kt",
"src/com/android/settings/*.java",
"src/com/android/settings/accessibility/**/*.java",
"src/com/android/settings/accounts/**/*.java",
"src/com/android/settings/applications/**/*.java",
"src/com/android/settings/backup/**/*.java",
"src/com/android/settings/bluetooth/**/*.java",
"src/com/android/settings/bluetooth/**/*.kt",
"src/com/android/settings/bugreporthandler/**/*.java",
"src/com/android/settings/communal/**/*.java",
"src/com/android/settings/connecteddevice/**/*.java",
//"src/com/android/settings/core/**/*.java",
"src/com/android/settings/dashboard/**/*.java",
"src/com/android/settings/datausage/**/*.java",
"src/com/android/settings/datetime/**/*.java",
"src/com/android/settings/deletionhelper/**/*.java",
//"src/com/android/settings/development/**/*.java",
"src/com/android/settings/deviceinfo/**/*.java",
"src/com/android/settings/devicelock/**/*.java",
"src/com/android/settings/display/**/*.java",
"src/com/android/settings/dream/**/*.java",
"src/com/android/settings/emergency/**/*.java",
"src/com/android/settings/enterprise/**/*.java",
"src/com/android/settings/flashlight/**/*.java",
"src/com/android/settings/fuelgauge/**/*.java",
"src/com/android/settings/gestures/**/*.java",
//"src/com/android/settings/homepage/**/*.java",
"src/com/android/settings/inputmethod/**/*.java",
"src/com/android/settings/network/ShadowServiceManagerExtend.java",
"src/com/android/settings/search/DatabaseIndexingUtils.java",
"src/com/android/settings/testutils/**/*.java",
],
// test_suites attribute is not needed. This module will be configured in ATP GCL file.
static_libs: [
"Robolectric_shadows_androidx_fragment_upstream",
"Settings_robolectric_meta_service_file",
"SettingsLib-robo-testutils",
"Settings-robo-testutils",
"Settings-testutils2",
"SettingsLib-robo-testutils",
"Settings_robolectric_meta_service_file",
"aconfig_settings_flags_lib",
"android.webkit.flags-aconfig-java",
"androidx.test.core",
"androidx.test.espresso.core",
"androidx.test.ext.junit",
"androidx.test.rules",
"androidx.test.runner",
"com_android_server_accessibility_flags_lib",
"flag-junit",
"flag-junit-base",
"aconfig_settings_flags_lib",
"platform-test-annotations",
"Settings-testutils2",
"notification_flags_lib",
"com_android_server_accessibility_flags_lib",
"platform-test-annotations",
"testables",
],
libs: [
"ims-common",
"android.test.mock",
"ims-common",
],
java_resource_dirs: [

View File

@@ -16,9 +16,13 @@
package com.android.settings.accounts;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
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;
@@ -30,6 +34,7 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import androidx.collection.ArraySet;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
@@ -51,9 +56,13 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import java.util.Set;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
com.android.settings.testutils.shadow.ShadowFragment.class,
ShadowAccountManager.class,
ShadowContentResolver.class,
})
public class AccountTypePreferenceLoaderTest {
@@ -63,6 +72,8 @@ public class AccountTypePreferenceLoaderTest {
private PreferenceFragmentCompat mPreferenceFragment;
@Mock
private PackageManager mPackageManager;
@Mock
private PreferenceManager mManager;
private Context mContext;
private Account mAccount;
@@ -91,18 +102,16 @@ public class AccountTypePreferenceLoaderTest {
}
@Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void updatePreferenceIntents_shouldRunRecursively() {
final PreferenceManager preferenceManager = mock(PreferenceManager.class);
// Top level
PreferenceGroup prefRoot = spy(new PreferenceScreen(mContext, null));
when(prefRoot.getPreferenceManager()).thenReturn(preferenceManager);
when(prefRoot.getPreferenceManager()).thenReturn(mManager);
Preference pref1 = mock(Preference.class);
PreferenceGroup prefGroup2 = spy(new PreferenceScreen(mContext, null));
when(prefGroup2.getPreferenceManager()).thenReturn(preferenceManager);
when(prefGroup2.getPreferenceManager()).thenReturn(mManager);
Preference pref3 = mock(Preference.class);
PreferenceGroup prefGroup4 = spy(new PreferenceScreen(mContext, null));
when(prefGroup4.getPreferenceManager()).thenReturn(preferenceManager);
when(prefGroup4.getPreferenceManager()).thenReturn(mManager);
prefRoot.addPreference(pref1);
prefRoot.addPreference(prefGroup2);
prefRoot.addPreference(pref3);
@@ -114,7 +123,7 @@ public class AccountTypePreferenceLoaderTest {
prefGroup2.addPreference(pref21);
prefGroup2.addPreference(pref22);
PreferenceGroup prefGroup41 = spy(new PreferenceScreen(mContext, null));
when(prefGroup41.getPreferenceManager()).thenReturn(preferenceManager);
when(prefGroup41.getPreferenceManager()).thenReturn(mManager);
Preference pref42 = mock(Preference.class);
prefGroup4.addPreference(prefGroup41);
prefGroup4.addPreference(pref42);
@@ -132,4 +141,113 @@ public class AccountTypePreferenceLoaderTest {
verify(mPrefLoader).updatePreferenceIntents(prefGroup4, acctType, mAccount);
verify(mPrefLoader).updatePreferenceIntents(prefGroup41, acctType, mAccount);
}
@Test
public void generateFragmentAllowlist_nullPrefGroup_emptyList() {
Set<String> allowed = mPrefLoader.generateFragmentAllowlist(null);
assertThat(allowed).isEmpty();
}
@Test
public void generateFragmentAllowlist_simpleGroupNoFragment_emptyList() {
Preference pref = new Preference(mContext);
PreferenceScreen screen = spy(new PreferenceScreen(mContext, null));
when(screen.getPreferenceManager()).thenReturn(mManager);
screen.addPreference(pref);
Set<String> allowed = mPrefLoader.generateFragmentAllowlist(screen);
assertThat(allowed).isEmpty();
}
@Test
public void generateFragmentAllowlist_simpleGroupOneFragment_populatedList() {
Preference pref = new Preference(mContext);
pref.setFragment("test");
PreferenceScreen screen = spy(new PreferenceScreen(mContext, null));
when(screen.getPreferenceManager()).thenReturn(mManager);
screen.addPreference(pref);
Set<String> allowed = mPrefLoader.generateFragmentAllowlist(screen);
assertThat(allowed).isNotEmpty();
}
@Test
public void generateFragmentAllowlist_nestedGroupWithFragments_populatedList() {
Preference pref = new Preference(mContext);
pref.setFragment("test");
PreferenceScreen nested = spy(new PreferenceScreen(mContext, null));
PreferenceScreen parent = spy(new PreferenceScreen(mContext, null));
when(nested.getPreferenceManager()).thenReturn(mManager);
when(parent.getPreferenceManager()).thenReturn(mManager);
parent.addPreference(nested);
nested.addPreference(pref);
Set<String> allowed = mPrefLoader.generateFragmentAllowlist(parent);
assertThat(allowed).isNotEmpty();
}
@Test
public void filterBlockedFragments_nullPrefGroup_noop() {
// verify no NPE
mPrefLoader.filterBlockedFragments(null, new ArraySet<>());
}
@Test
public void filterBlockedFragments_simplePrefGroupNoFragment_noop() {
Preference pref = spy(new Preference(mContext));
PreferenceScreen screen = spy(new PreferenceScreen(mContext, null));
when(screen.getPreferenceManager()).thenReturn(mManager);
screen.addPreference(pref);
mPrefLoader.filterBlockedFragments(screen, new ArraySet<>());
verify(screen, never()).setOnPreferenceClickListener(any());
verify(pref, never()).setOnPreferenceClickListener(any());
}
@Test
public void filterBlockedFragments_simplePrefGroupWithAllowedFragment_noop() {
Preference pref = spy(new Preference(mContext));
pref.setFragment("test");
PreferenceScreen screen = spy(new PreferenceScreen(mContext, null));
when(screen.getPreferenceManager()).thenReturn(mManager);
screen.addPreference(pref);
mPrefLoader.filterBlockedFragments(screen, Set.of("test"));
verify(screen, never()).setOnPreferenceClickListener(any());
verify(pref, never()).setOnPreferenceClickListener(any());
}
@Test
public void filterBlockedFragments_simplePrefGroupNoMatchFragment_overrideClick() {
Preference pref = spy(new Preference(mContext));
pref.setFragment("test");
PreferenceScreen screen = spy(new PreferenceScreen(mContext, null));
when(screen.getPreferenceManager()).thenReturn(mManager);
screen.addPreference(pref);
mPrefLoader.filterBlockedFragments(screen, new ArraySet<>());
verify(pref).setOnPreferenceClickListener(any());
}
@Test
public void filterBlockedFragments_nestedPrefGroupWithNoMatchFragment_overrideClick() {
Preference pref = spy(new Preference(mContext));
pref.setFragment("test");
PreferenceScreen nested = spy(new PreferenceScreen(mContext, null));
PreferenceScreen parent = spy(new PreferenceScreen(mContext, null));
when(nested.getPreferenceManager()).thenReturn(mManager);
when(parent.getPreferenceManager()).thenReturn(mManager);
parent.addPreference(nested);
nested.addPreference(pref);
mPrefLoader.filterBlockedFragments(parent, Set.of("nomatch", "other"));
verify(pref).setOnPreferenceClickListener(any());
}
}

View File

@@ -272,7 +272,7 @@ public class BatteryOptimizeUtilsTest {
}
@Test
public void testResetAppOptimizationMode_Optimized_verifyAction() throws Exception {
public void testResetAppOptimizationModeInternal_Optimized_verifyAction() throws Exception {
runTestForResetWithMode(
AppOpsManager.MODE_ALLOWED, /* allowListed */
false,
@@ -287,7 +287,8 @@ public class BatteryOptimizeUtilsTest {
}
@Test
public void testResetAppOptimizationMode_SystemOrDefault_verifyAction() throws Exception {
public void testResetAppOptimizationModeInternal_SystemOrDefault_verifyAction()
throws Exception {
runTestForResetWithMode(
AppOpsManager.MODE_ALLOWED, /* allowListed */
true,
@@ -304,7 +305,7 @@ public class BatteryOptimizeUtilsTest {
}
@Test
public void testResetAppOptimizationMode_Restricted_verifyAction() throws Exception {
public void testResetAppOptimizationModeInternal_Restricted_verifyAction() throws Exception {
runTestForResetWithMode(
AppOpsManager.MODE_IGNORED, /* allowListed */
false,
@@ -315,7 +316,7 @@ public class BatteryOptimizeUtilsTest {
}
@Test
public void testResetAppOptimizationMode_Unrestricted_verifyAction() throws Exception {
public void testResetAppOptimizationModeInternal_Unrestricted_verifyAction() throws Exception {
runTestForResetWithMode(
AppOpsManager.MODE_ALLOWED, /* allowListed */
true,
@@ -346,7 +347,7 @@ public class BatteryOptimizeUtilsTest {
doReturn(isSystemOrDefaultApp).when(mMockBackend).isSysAllowlisted(anyString());
doReturn(isSystemOrDefaultApp).when(mMockBackend).isDefaultActiveApp(anyString(), anyInt());
BatteryOptimizeUtils.resetAppOptimizationMode(
BatteryOptimizeUtils.resetAppOptimizationModeInternal(
mContext,
mMockIPackageManager,
mMockAppOpsManager,

View File

@@ -18,6 +18,7 @@ package com.android.settings.fuelgauge.batteryusage
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.fuelgauge.BatteryOptimizeHistoricalLogEntry.Action
import com.android.settings.fuelgauge.BatteryOptimizeUtils
import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_OPTIMIZED
@@ -26,6 +27,7 @@ import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNKNOWN
import com.android.settings.fuelgauge.BatteryOptimizeUtils.MODE_UNRESTRICTED
import com.android.settings.fuelgauge.batteryusage.AppOptModeSharedPreferencesUtils.UNLIMITED_EXPIRE_TIME
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -39,9 +41,8 @@ import org.mockito.Mockito.`when` as whenever
import org.mockito.Spy
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class)
@RunWith(AndroidJUnit4::class)
class AppOptModeSharedPreferencesUtilsTest {
@get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule()
@@ -52,7 +53,12 @@ class AppOptModeSharedPreferencesUtilsTest {
@Before
fun setup() {
AppOptModeSharedPreferencesUtils.deleteAppOptimizationModeEventByUid(context, UID)
AppOptModeSharedPreferencesUtils.clearAll(context)
}
@After
fun tearDown() {
AppOptModeSharedPreferencesUtils.clearAll(context)
}
@Test
@@ -60,6 +66,16 @@ class AppOptModeSharedPreferencesUtilsTest {
assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty()
}
@Test
fun clearAll_withData_verifyCleared() {
insertAppOptModeEventForTest(expirationTime = 1000L)
assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).hasSize(1)
AppOptModeSharedPreferencesUtils.clearAll(context)
assertThat(AppOptModeSharedPreferencesUtils.getAllEvents(context)).isEmpty()
}
@Test
fun updateAppOptModeExpirationInternal_withExpirationTime_verifyData() {
insertAppOptModeEventForTest(expirationTime = 1000L)

View File

@@ -43,6 +43,7 @@ import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -390,7 +391,7 @@ public class ProviderModelSliceTest {
}
private PendingIntent getPrimaryAction() {
final Intent intent = new Intent("android.settings.NETWORK_PROVIDER_SETTINGS")
final Intent intent = new Intent(Settings.ACTION_NETWORK_PROVIDER_SETTINGS)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
return PendingIntent.getActivity(mContext, 0 /* requestCode */,
intent, PendingIntent.FLAG_IMMUTABLE /* flags */);

View File

@@ -33,8 +33,10 @@ import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Flags;
import android.os.RemoteException;
import android.os.UserManager;
@@ -432,6 +434,36 @@ public class PrivateSpaceMaintainerTest {
assertThat(getSecureSkipFirstUseHints()).isEqualTo(1);
}
@Test
public void createPrivateSpace_psDoesNotExist_setsPrivateSpaceSettingsComponentDisabled() {
mSetFlagsRule.enableFlags(
android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES);
assumeTrue(mContext.getSystemService(UserManager.class).canAddPrivateProfile());
PrivateSpaceMaintainer privateSpaceMaintainer =
PrivateSpaceMaintainer.getInstance(mContext);
privateSpaceMaintainer.createPrivateSpace();
assertThat(privateSpaceMaintainer.getPrivateProfileHandle()).isNotNull();
Context privateSpaceUserContext = mContext.createContextAsUser(
privateSpaceMaintainer.getPrivateProfileHandle(),
/* flags */ 0);
// Assert that private space settings launcher app icon is disabled
ComponentName settingsComponentName = new ComponentName(privateSpaceUserContext,
com.android.settings.Settings.class);
int settingsComponentEnabledSetting = privateSpaceUserContext.getPackageManager()
.getComponentEnabledSetting(settingsComponentName);
assertThat(settingsComponentEnabledSetting)
.isEqualTo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
// Assert that private space settings create shortcut activity is disabled
ComponentName shortcutPickerComponentName = new ComponentName(privateSpaceUserContext,
com.android.settings.Settings.CreateShortcutActivity.class);
int settingsShortcutPickerEnabledSetting = privateSpaceUserContext.getPackageManager()
.getComponentEnabledSetting(shortcutPickerComponentName);
assertThat(settingsShortcutPickerEnabledSetting)
.isEqualTo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
}
@Test
public void createPrivateSpace_pSExists_doesNotChangeSkipFirstUseHints() {
mSetFlagsRule.enableFlags(

View File

@@ -497,6 +497,8 @@ public class WifiHotspotRepositoryTest {
SparseIntArray channels = mSoftApConfigCaptor.getValue().getChannels();
assertThat(channels.get(BAND_2GHZ, CHANNEL_NOT_FOUND)).isNotEqualTo(CHANNEL_NOT_FOUND);
assertThat(channels.get(BAND_2GHZ_5GHZ, CHANNEL_NOT_FOUND)).isNotEqualTo(CHANNEL_NOT_FOUND);
assertThat(mSoftApConfigCaptor.getValue().getSecurityType())
.isEqualTo(SECURITY_TYPE_WPA3_SAE_TRANSITION);
}
@Test