diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 4b38062c4f4..2b2a1b82490 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -2686,6 +2686,7 @@ @@ -2696,18 +2697,22 @@ + android:permission="android.permission.NETWORK_SETTINGS" + android:theme="@style/Theme.SpaLib.Dialog"> diff --git a/res/values/strings.xml b/res/values/strings.xml index 408ba8c812f..0f62fc66c39 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10142,6 +10142,9 @@ ^1 data warning / ^2 data limit + + Carrier data accounting may differ from device accounting + Excludes data used by carrier networks @@ -11713,8 +11716,6 @@ Satellite messaging may take longer and is available only in some areas. Weather and certain structures may affect your satellite connection. Calling by satellite isn\u2019t available. Emergency calls may still connect.\n\nIt may take some time for account changes to show in Settings. Contact your carrier for details. More about satellite messaging - - Access Point Names diff --git a/res/xml/accessibility_text_reading_options.xml b/res/xml/accessibility_text_reading_options.xml index 795c4ffb9fc..1f8c24bf192 100644 --- a/res/xml/accessibility_text_reading_options.xml +++ b/res/xml/accessibility_text_reading_options.xml @@ -56,8 +56,8 @@ + android:summary="@string/accessibility_toggle_maximize_text_contrast_preference_summary" + android:title="@string/accessibility_toggle_maximize_text_contrast_preference_title" /> diff --git a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java index 5976ef51317..a90af2182f7 100644 --- a/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java +++ b/src/com/android/settings/accessibility/TextReadingPreferenceFragment.java @@ -117,11 +117,6 @@ public class TextReadingPreferenceFragment extends DashboardFragment { } } } - - if (Flags.enableColorContrastControl()) { - // High text contrast toggle will be added inside Color Contrast page on V+. - removePreference(HIGH_TEXT_CONTRAST_KEY); - } } @Override @@ -208,12 +203,10 @@ public class TextReadingPreferenceFragment extends DashboardFragment { mFontWeightAdjustmentController.setEntryPoint(mEntryPoint); controllers.add(mFontWeightAdjustmentController); - if (!Flags.enableColorContrastControl()) { - final HighTextContrastPreferenceController highTextContrastController = - new HighTextContrastPreferenceController(context, HIGH_TEXT_CONTRAST_KEY); - highTextContrastController.setEntryPoint(mEntryPoint); - controllers.add(highTextContrastController); - } + final HighTextContrastPreferenceController highTextContrastController = + new HighTextContrastPreferenceController(context, HIGH_TEXT_CONTRAST_KEY); + highTextContrastController.setEntryPoint(mEntryPoint); + controllers.add(highTextContrastController); final TextReadingResetController resetController = new TextReadingResetController(context, RESET_KEY, diff --git a/src/com/android/settings/datausage/DataUsageList.kt b/src/com/android/settings/datausage/DataUsageList.kt index 3083fb75443..1995097d6f1 100644 --- a/src/com/android/settings/datausage/DataUsageList.kt +++ b/src/com/android/settings/datausage/DataUsageList.kt @@ -34,6 +34,7 @@ import com.android.settings.dashboard.DashboardFragment import com.android.settings.datausage.lib.BillingCycleRepository import com.android.settings.datausage.lib.NetworkUsageData import com.android.settings.network.MobileNetworkRepository +import com.android.settings.network.SubscriptionUtil import com.android.settings.network.mobileDataEnabledFlow import com.android.settingslib.mobile.dataservice.SubscriptionInfoEntity import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle @@ -95,6 +96,18 @@ open class DataUsageList : DashboardFragment() { } chartDataUsagePreferenceController = use(ChartDataUsagePreferenceController::class.java) .apply { init(template) } + + updateWarning() + } + + private fun updateWarning() { + val template = template ?: return + val warningPreference = findPreference(KEY_WARNING)!! + if (template.matchRule != NetworkTemplate.MATCH_WIFI) { + warningPreference.setSummary(R.string.operator_warning) + } else if (SubscriptionUtil.isSimHardwareVisible(context)) { + warningPreference.setSummary(R.string.non_carrier_data_usage_warning) + } } override fun onViewCreated(v: View, savedInstanceState: Bundle?) { @@ -188,5 +201,8 @@ open class DataUsageList : DashboardFragment() { private const val TAG = "DataUsageList" private const val KEY_USAGE_AMOUNT = "usage_amount" + + @VisibleForTesting + const val KEY_WARNING = "warning" } } diff --git a/src/com/android/settings/development/AdbQrcodeScannerFragment.java b/src/com/android/settings/development/AdbQrcodeScannerFragment.java index ca44747f163..1d384544447 100644 --- a/src/com/android/settings/development/AdbQrcodeScannerFragment.java +++ b/src/com/android/settings/development/AdbQrcodeScannerFragment.java @@ -16,6 +16,7 @@ package com.android.settings.development; +import android.annotation.Nullable; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; @@ -26,6 +27,7 @@ import android.debug.IAdbManager; import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.SurfaceTexture; +import android.net.wifi.WifiConfiguration; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -47,7 +49,6 @@ import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.wifi.dpp.AdbQrCode; import com.android.settings.wifi.dpp.WifiDppQrCodeBaseFragment; -import com.android.settings.wifi.dpp.WifiNetworkConfig; import com.android.settingslib.qrcode.QrCamera; import com.android.settingslib.qrcode.QrDecorateView; @@ -81,7 +82,8 @@ public class AdbQrcodeScannerFragment extends WifiDppQrCodeBaseFragment implemen /** QR code data scanned by camera */ private AdbQrCode mAdbQrCode; - private WifiNetworkConfig mAdbConfig; + @Nullable + private WifiConfiguration mAdbConfig; private IAdbManager mAdbManager; @@ -287,13 +289,16 @@ public class AdbQrcodeScannerFragment extends WifiDppQrCodeBaseFragment implemen AdbQrCode.triggerVibrationForQrCodeRecognition(getContext()); mVerifyingTextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); try { - mAdbManager.enablePairingByQrCode(mAdbConfig.getSsid(), - mAdbConfig.getPreSharedKey()); + if (mAdbConfig != null) { + mAdbManager.enablePairingByQrCode(mAdbConfig.SSID, + mAdbConfig.preSharedKey); + return; + } } catch (RemoteException e) { - Log.e(TAG, "Unable to enable QR code pairing"); - getActivity().setResult(Activity.RESULT_CANCELED); - getActivity().finish(); + Log.e(TAG, "Unable to enable QR code pairing" + e); } + getActivity().setResult(Activity.RESULT_CANCELED); + getActivity().finish(); } @Override diff --git a/src/com/android/settings/network/WepNetworkDialogActivity.kt b/src/com/android/settings/network/WepNetworkDialogActivity.kt index fef93ef7e96..d6fa7953887 100644 --- a/src/com/android/settings/network/WepNetworkDialogActivity.kt +++ b/src/com/android/settings/network/WepNetworkDialogActivity.kt @@ -27,18 +27,21 @@ import androidx.compose.ui.text.style.TextAlign import com.android.settings.R import com.android.settings.core.SubSettingLauncher import com.android.settings.wifi.ConfigureWifiSettings -import com.android.settingslib.spa.SpaBaseDialogActivity +import com.android.settingslib.spa.SpaDialogWindowTypeActivity import com.android.settingslib.spa.widget.dialog.AlertDialogButton -import com.android.settingslib.spa.widget.dialog.SettingsAlertDialogWithIcon +import com.android.settingslib.spa.widget.dialog.SettingsAlertDialogContent import com.android.settingslib.wifi.WifiUtils.Companion.SSID -class WepNetworkDialogActivity : SpaBaseDialogActivity() { +class WepNetworkDialogActivity : SpaDialogWindowTypeActivity() { + + // TODO: Set different window type when called from Quick Settings. + override val dialogWindowType = null + @Composable override fun Content() { val context = LocalContext.current val wifiManager = context.getSystemService(WifiManager::class.java) - SettingsAlertDialogWithIcon( - onDismissRequest = { finish() }, + SettingsAlertDialogContent( confirmButton = AlertDialogButton( getString(R.string.wifi_settings_ssid_block_button_close) ) { finish() }, @@ -67,4 +70,4 @@ class WepNetworkDialogActivity : SpaBaseDialogActivity() { ) }) } -} \ No newline at end of file +} diff --git a/src/com/android/settings/network/telephony/SatelliteSetting.java b/src/com/android/settings/network/telephony/SatelliteSetting.java index b6d018abb84..ad10e0377ea 100644 --- a/src/com/android/settings/network/telephony/SatelliteSetting.java +++ b/src/com/android/settings/network/telephony/SatelliteSetting.java @@ -16,6 +16,8 @@ package com.android.settings.network.telephony; +import static android.telephony.CarrierConfigManager.KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING; + import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.Intent; @@ -23,7 +25,9 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.os.PersistableBundle; import android.os.UserManager; +import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.satellite.SatelliteManager; @@ -60,7 +64,9 @@ public class SatelliteSetting extends RestrictedDashboardFragment { private Activity mActivity; private TelephonyManager mTelephonymanager; + private CarrierConfigManager mCarrierConfigManager; private SatelliteManager mSatelliteManager; + private PersistableBundle mConfigBundle; private int mSubId; public SatelliteSetting() { @@ -78,6 +84,7 @@ public class SatelliteSetting extends RestrictedDashboardFragment { mActivity = getActivity(); mTelephonymanager = mActivity.getSystemService(TelephonyManager.class); + mCarrierConfigManager = mActivity.getSystemService(CarrierConfigManager.class); mSatelliteManager = mActivity.getSystemService(SatelliteManager.class); mSubId = mActivity.getIntent().getIntExtra(SUB_ID, SubscriptionManager.INVALID_SUBSCRIPTION_ID); @@ -134,7 +141,7 @@ public class SatelliteSetting extends RestrictedDashboardFragment { preference.setSummary(spannable); /* The link will lead users to a guide page */ preference.setOnPreferenceClickListener(pref -> { - String url = getResources().getString(R.string.more_info_satellite_messaging_link); + String url = readSatelliteMoreInfoString(mSubId); if (!url.isEmpty()) { Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); @@ -163,7 +170,7 @@ public class SatelliteSetting extends RestrictedDashboardFragment { operatorName)); final String[] link = new String[1]; - link[0] = getResources().getString(R.string.more_info_satellite_messaging_link); + link[0] = readSatelliteMoreInfoString(mSubId); footerPreference.setLearnMoreAction(view -> { if (!link[0].isEmpty()) { Intent helpIntent = HelpUtils.getHelpIntent(mActivity, link[0], @@ -192,6 +199,18 @@ public class SatelliteSetting extends RestrictedDashboardFragment { } } + private String readSatelliteMoreInfoString(int subId) { + if (mConfigBundle == null) { + mConfigBundle = mCarrierConfigManager.getConfigForSubId(subId, + KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING); + if (mConfigBundle.isEmpty()) { + Log.d(TAG, "SatelliteSettings: getDefaultConfig"); + mConfigBundle = CarrierConfigManager.getDefaultConfig(); + } + } + return mConfigBundle.getString(KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING, ""); + } + private static void loge(String message) { Log.e(TAG, message); } diff --git a/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt b/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt index 1ed595909e0..d6399790d92 100644 --- a/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt +++ b/src/com/android/settings/spa/app/appinfo/AppInfoSettingsMoreOptions.kt @@ -20,6 +20,7 @@ import android.app.AppOpsManager import android.app.ecm.EnhancedConfirmationManager import android.content.Context import android.content.pm.ApplicationInfo +import android.content.pm.PackageManager import android.os.UserManager import android.widget.Toast import androidx.compose.runtime.Composable @@ -180,7 +181,12 @@ private fun ApplicationInfo.shouldShowAccessRestrictedSettings(context: Context) return if (android.permission.flags.Flags.enhancedConfirmationModeApisEnabled() && android.security.Flags.extendEcmToAllSettings()) { val manager = context.getSystemService(EnhancedConfirmationManager::class.java)!! - manager.isClearRestrictionAllowed(packageName) + try { + manager.isClearRestrictionAllowed(packageName) + } catch (e: PackageManager.NameNotFoundException) { + // Package might have been archived + false + } } else { context.appOpsManager.noteOpNoThrow( AppOpsManager.OP_ACCESS_RESTRICTED_SETTINGS, uid, packageName, null, null diff --git a/src/com/android/settings/wifi/AddNetworkFragment.java b/src/com/android/settings/wifi/AddNetworkFragment.java index 9fd8626f3bf..f5bf5eec9df 100644 --- a/src/com/android/settings/wifi/AddNetworkFragment.java +++ b/src/com/android/settings/wifi/AddNetworkFragment.java @@ -16,12 +16,17 @@ package com.android.settings.wifi; +import static android.os.UserManager.DISALLOW_ADD_WIFI_CONFIG; + import android.app.Activity; import android.app.settings.SettingsEnums; +import android.content.Context; import android.content.Intent; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.Bundle; +import android.os.UserManager; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -43,6 +48,7 @@ import com.android.settings.wifi.dpp.WifiDppUtils; */ public class AddNetworkFragment extends InstrumentedFragment implements WifiConfigUiBase2, View.OnClickListener { + private static final String TAG = "AddNetworkFragment"; public static final String WIFI_CONFIG_KEY = "wifi_config_key"; @VisibleForTesting @@ -62,6 +68,10 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (!isAddWifiConfigAllowed(getContext())) { + getActivity().finish(); + return; + } } @Override @@ -237,4 +247,14 @@ public class AddNetworkFragment extends InstrumentedFragment implements WifiConf activity.setResult(Activity.RESULT_CANCELED); activity.finish(); } + + @VisibleForTesting + static boolean isAddWifiConfigAllowed(Context context) { + UserManager userManager = context.getSystemService(UserManager.class); + if (userManager != null && userManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)) { + Log.e(TAG, "The user is not allowed to add Wi-Fi configuration."); + return false; + } + return true; + } } diff --git a/src/com/android/settings/wifi/dpp/AdbQrCode.java b/src/com/android/settings/wifi/dpp/AdbQrCode.java index 65577874e20..2d830b2820a 100644 --- a/src/com/android/settings/wifi/dpp/AdbQrCode.java +++ b/src/com/android/settings/wifi/dpp/AdbQrCode.java @@ -16,8 +16,12 @@ package com.android.settings.wifi.dpp; import android.content.Context; +import android.net.wifi.UriParserResults; +import android.net.wifi.WifiConfiguration; import android.text.TextUtils; +import androidx.annotation.NonNull; + /** * Extension of WifiQrCode to support ADB QR code format. * It will be based on the ZXing format: @@ -27,31 +31,31 @@ import android.text.TextUtils; public class AdbQrCode extends WifiQrCode { static final String SECURITY_ADB = "ADB"; - private WifiNetworkConfig mAdbConfig; + private WifiConfiguration mAdbConfig; public AdbQrCode(String qrCode) throws IllegalArgumentException { super(qrCode); // Only accept the zxing format. - if (!WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(getScheme())) { + if (getScheme() != UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG) { throw new IllegalArgumentException("DPP format not supported for ADB QR code"); } + mAdbConfig = getWifiConfiguration(); - mAdbConfig = getWifiNetworkConfig(); - if (!SECURITY_ADB.equals(mAdbConfig.getSecurity())) { - throw new IllegalArgumentException("Invalid security type"); + if (mAdbConfig == null) { + throw new IllegalArgumentException("Null config when parsing ADB QR code"); } - - if (TextUtils.isEmpty(mAdbConfig.getSsid())) { + if (TextUtils.isEmpty(mAdbConfig.SSID)) { throw new IllegalArgumentException("Empty service name"); } - if (TextUtils.isEmpty(mAdbConfig.getPreSharedKey())) { + if (TextUtils.isEmpty(mAdbConfig.preSharedKey)) { throw new IllegalArgumentException("Empty password"); } } - public WifiNetworkConfig getAdbNetworkConfig() { + @NonNull + public WifiConfiguration getAdbNetworkConfig() { return mAdbConfig; } diff --git a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java index e6f0b31f384..a7527d7332f 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java +++ b/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivity.java @@ -16,6 +16,8 @@ package com.android.settings.wifi.dpp; +import static android.os.UserManager.DISALLOW_ADD_WIFI_CONFIG; + import android.app.settings.SettingsEnums; import android.content.Context; import android.content.Intent; @@ -99,6 +101,10 @@ public class WifiDppConfiguratorActivity extends WifiDppBaseActivity implements @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (!isAddWifiConfigAllowed(getApplicationContext())) { + finish(); + return; + } if (savedInstanceState != null) { String qrCode = savedInstanceState.getString(KEY_QR_CODE); @@ -119,6 +125,10 @@ public class WifiDppConfiguratorActivity extends WifiDppBaseActivity implements @Override protected void handleIntent(Intent intent) { + if (!isAddWifiConfigAllowed(getApplicationContext())) { + finish(); + return; + } if (isGuestUser(getApplicationContext())) { Log.e(TAG, "Guest user is not allowed to configure Wi-Fi!"); EventLog.writeEvent(0x534e4554, "224772890", -1 /* UID */, "User is a guest"); @@ -402,4 +412,14 @@ public class WifiDppConfiguratorActivity extends WifiDppBaseActivity implements if (userManager == null) return false; return userManager.isGuestUser(); } + + @VisibleForTesting + static boolean isAddWifiConfigAllowed(Context context) { + UserManager userManager = context.getSystemService(UserManager.class); + if (userManager != null && userManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)) { + Log.e(TAG, "The user is not allowed to add Wi-Fi configuration."); + return false; + } + return true; + } } diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java index 479c81dafa1..34948dc69dc 100644 --- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java +++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java @@ -26,6 +26,7 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.net.wifi.EasyConnectStatusCallback; +import android.net.wifi.UriParserResults; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; import android.os.Bundle; @@ -183,32 +184,29 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl // one for open network and one for enhanced open network. final WifiManager wifiManager = context.getSystemService(WifiManager.class); - final WifiNetworkConfig qrCodeWifiNetworkConfig = - (WifiNetworkConfig)msg.obj; - final List qrCodeWifiConfigurations = - qrCodeWifiNetworkConfig.getWifiConfigurations(); + final WifiConfiguration qrCodeWifiConfiguration = (WifiConfiguration) msg.obj; // Adds all Wi-Fi networks in QR code to the set of configured networks and // connects to it if it's reachable. boolean hasHiddenOrReachableWifiNetwork = false; - for (WifiConfiguration qrCodeWifiConfiguration : qrCodeWifiConfigurations) { - final int id = wifiManager.addNetwork(qrCodeWifiConfiguration); - if (id == -1) { - continue; - } + final int id = wifiManager.addNetwork(qrCodeWifiConfiguration); + if (id == -1) { + return; + } - if (!canConnectWifi(qrCodeWifiConfiguration.SSID)) return; + if (!canConnectWifi(qrCodeWifiConfiguration.SSID)) { + return; + } - wifiManager.enableNetwork(id, /* attemptConnect */ false); - // WifiTracker only contains a hidden SSID Wi-Fi network if it's saved. - // We can't check if a hidden SSID Wi-Fi network is reachable in advance. - if (qrCodeWifiConfiguration.hiddenSSID || - isReachableWifiNetwork(qrCodeWifiConfiguration)) { - hasHiddenOrReachableWifiNetwork = true; - mEnrolleeWifiConfiguration = qrCodeWifiConfiguration; - wifiManager.connect(id, - /* listener */ WifiDppQrCodeScannerFragment.this); - } + wifiManager.enableNetwork(id, /* attemptConnect */ false); + // WifiTracker only contains a hidden SSID Wi-Fi network if it's saved. + // We can't check if a hidden SSID Wi-Fi network is reachable in advance. + if (qrCodeWifiConfiguration.hiddenSSID + || isReachableWifiNetwork(qrCodeWifiConfiguration)) { + hasHiddenOrReachableWifiNetwork = true; + mEnrolleeWifiConfiguration = qrCodeWifiConfiguration; + wifiManager.connect(id, + /* listener */ WifiDppQrCodeScannerFragment.this); } if (!hasHiddenOrReachableWifiNetwork) { @@ -530,8 +528,9 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl } // It's impossible to provision other device with ZXing Wi-Fi Network config format - final String scheme = mWifiQrCode.getScheme(); - if (mIsConfiguratorMode && WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(scheme)) { + if (mIsConfiguratorMode + && mWifiQrCode.getScheme() + == UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG) { showErrorMessage(R.string.wifi_dpp_qr_code_is_not_valid_format); return false; } @@ -545,11 +544,11 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl @Override public void handleSuccessfulResult(String qrCode) { switch (mWifiQrCode.getScheme()) { - case WifiQrCode.SCHEME_DPP: + case UriParserResults.URI_SCHEME_DPP: handleWifiDpp(); break; - case WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG: + case UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG: handleZxingWifiFormat(); break; @@ -567,7 +566,7 @@ public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment impl private void handleZxingWifiFormat() { Message message = mHandler.obtainMessage(MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS); - message.obj = new WifiQrCode(mWifiQrCode.getQrCode()).getWifiNetworkConfig(); + message.obj = new WifiQrCode(mWifiQrCode.getQrCode()).getWifiConfiguration(); mHandler.sendMessageDelayed(message, SHOW_SUCCESS_SQUARE_INTERVAL); } diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java index 70ac96c9025..9b93480fd68 100644 --- a/src/com/android/settings/wifi/dpp/WifiQrCode.java +++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java @@ -16,14 +16,12 @@ package com.android.settings.wifi.dpp; +import android.annotation.NonNull; +import android.net.wifi.UriParserResults; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiUriParser; import android.text.TextUtils; - -import androidx.annotation.VisibleForTesting; - -import java.util.Arrays; -import java.util.List; -import java.util.regex.Pattern; +import android.util.Log; /** * Supports to parse 2 types of QR code @@ -70,19 +68,8 @@ public class WifiQrCode { static final String SECURITY_SAE = "SAE"; private String mQrCode; - - /** - * SCHEME_DPP for standard Wi-Fi device provision protocol; SCHEME_ZXING_WIFI_NETWORK_CONFIG - * for ZXing reader library' Wi-Fi Network config format - */ - private String mScheme; - - // Data from parsed Wi-Fi DPP QR code - private String mPublicKey; - private String mInformation; - - // Data from parsed ZXing reader library's Wi-Fi Network config format - private WifiNetworkConfig mWifiNetworkConfig; + @NonNull + private UriParserResults mUriParserResults; public WifiQrCode(String qrCode) throws IllegalArgumentException { if (TextUtils.isEmpty(qrCode)) { @@ -90,111 +77,14 @@ public class WifiQrCode { } mQrCode = qrCode; - - if (qrCode.startsWith(PREFIX_DPP)) { - mScheme = SCHEME_DPP; - parseWifiDppQrCode(qrCode); - } else if (qrCode.startsWith(PREFIX_ZXING_WIFI_NETWORK_CONFIG)) { - mScheme = SCHEME_ZXING_WIFI_NETWORK_CONFIG; - parseZxingWifiQrCode(qrCode); - } else { + try { + mUriParserResults = WifiUriParser.parseUri(mQrCode); + Log.i("WifiQrCode", "mUriParserResults = " + mUriParserResults); + } catch (IllegalArgumentException ie) { throw new IllegalArgumentException("Invalid scheme"); } } - /** Parses Wi-Fi DPP QR code string */ - private void parseWifiDppQrCode(String qrCode) throws IllegalArgumentException { - List keyValueList = getKeyValueList(qrCode, PREFIX_DPP, DELIMITER_QR_CODE); - - String publicKey = getValueOrNull(keyValueList, PREFIX_DPP_PUBLIC_KEY); - if (TextUtils.isEmpty(publicKey)) { - throw new IllegalArgumentException("Invalid format"); - } - mPublicKey = publicKey; - - mInformation = getValueOrNull(keyValueList, PREFIX_DPP_INFORMATION); - } - - /** Parses ZXing reader library's Wi-Fi Network config format */ - private void parseZxingWifiQrCode(String qrCode) throws IllegalArgumentException { - List keyValueList = getKeyValueList(qrCode, PREFIX_ZXING_WIFI_NETWORK_CONFIG, - DELIMITER_QR_CODE); - - String security = getValueOrNull(keyValueList, PREFIX_ZXING_SECURITY); - String ssid = getValueOrNull(keyValueList, PREFIX_ZXING_SSID); - String password = getValueOrNull(keyValueList, PREFIX_ZXING_PASSWORD); - String hiddenSsidString = getValueOrNull(keyValueList, PREFIX_ZXING_HIDDEN_SSID); - - boolean hiddenSsid = "true".equalsIgnoreCase(hiddenSsidString); - - //"\", ";", "," and ":" are escaped with a backslash "\", should remove at first - security = removeBackSlash(security); - ssid = removeBackSlash(ssid); - password = removeBackSlash(password); - - mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid, password, - hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID, /* isHotspot */ false); - - if (mWifiNetworkConfig == null) { - throw new IllegalArgumentException("Invalid format"); - } - } - - /** - * Splits key/value pairs from qrCode - * - * @param qrCode the QR code raw string - * @param prefixQrCode the string before all key/value pairs in qrCode - * @param delimiter the string to split key/value pairs, can't contain a backslash - * @return a list contains string of key/value (e.g. K:key1) - */ - private List getKeyValueList(String qrCode, String prefixQrCode, - String delimiter) { - String keyValueString = qrCode.substring(prefixQrCode.length()); - - // Should not treat \delimiter as a delimiter - String regex = "(? keyValueList, String prefix) { - for (String keyValue : keyValueList) { - String strippedKeyValue = keyValue.stripLeading(); - if (strippedKeyValue.startsWith(prefix)) { - return strippedKeyValue.substring(prefix.length()); - } - } - - return null; - } - - @VisibleForTesting - String removeBackSlash(String input) { - if (input == null) { - return null; - } - - StringBuilder sb = new StringBuilder(); - boolean backSlash = false; - for (char ch : input.toCharArray()) { - if (ch != '\\') { - sb.append(ch); - backSlash = false; - } else { - if (backSlash) { - sb.append(ch); - backSlash = false; - continue; - } - - backSlash = true; - } - } - - return sb.toString(); - } - String getQrCode() { return mQrCode; } @@ -205,28 +95,23 @@ public class WifiQrCode { * SCHEME_DPP for standard Wi-Fi device provision protocol; SCHEME_ZXING_WIFI_NETWORK_CONFIG * for ZXing reader library' Wi-Fi Network config format */ - public String getScheme() { - return mScheme; + public int getScheme() { + return mUriParserResults.getUriScheme(); } /** Available when {@code getScheme()} returns SCHEME_DPP */ - @VisibleForTesting String getPublicKey() { - return mPublicKey; + return mUriParserResults.getPublicKey(); } /** May be available when {@code getScheme()} returns SCHEME_DPP */ public String getInformation() { - return mInformation; + return mUriParserResults.getInformation(); } /** Available when {@code getScheme()} returns SCHEME_ZXING_WIFI_NETWORK_CONFIG */ - WifiNetworkConfig getWifiNetworkConfig() { - if (mWifiNetworkConfig == null) { - return null; - } - - return new WifiNetworkConfig(mWifiNetworkConfig); + WifiConfiguration getWifiConfiguration() { + return mUriParserResults.getWifiConfiguration(); } static WifiQrCode getValidWifiDppQrCodeOrNull(String qrCode) { diff --git a/tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt index 29ec0eed352..7274eaa995f 100644 --- a/tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt +++ b/tests/spa_unit/src/com/android/settings/datausage/DataUsageListTest.kt @@ -26,8 +26,11 @@ import androidx.core.os.bundleOf import androidx.fragment.app.testing.launchFragment import androidx.fragment.app.testing.withFragment import androidx.lifecycle.Lifecycle +import androidx.preference.Preference import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.android.settings.R +import com.android.settings.datausage.DataUsageList.Companion.KEY_WARNING import com.android.settingslib.spaprivileged.framework.common.userManager import com.google.common.truth.Truth.assertThat import org.junit.Before @@ -38,12 +41,14 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.spy import org.mockito.kotlin.stub -private val mockUserManager: UserManager = mock() +private val mockUserManager = mock() -private val mockContext: Context = spy(ApplicationProvider.getApplicationContext()) { +private val spyContext: Context = spy(ApplicationProvider.getApplicationContext()) { on { userManager } doReturn mockUserManager } +private val spyResources = spy(spyContext.resources) + private var fakeIntent = Intent() @RunWith(AndroidJUnit4::class) @@ -51,6 +56,9 @@ class DataUsageListTest { @Before fun setUp() { + spyContext.stub { + on { resources } doReturn spyResources + } mockUserManager.stub { on { isGuestUser } doReturn false } @@ -122,10 +130,60 @@ class DataUsageListTest { assertThat(activity!!.isFinishing).isFalse() } } + + @Test + fun warning_wifiAndHasSim_displayNonCarrierWarning() { + val template = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build() + spyResources.stub { + on { getBoolean(R.bool.config_show_sim_info) } doReturn true + } + fakeIntent = Intent().apply { + putExtra(Settings.EXTRA_NETWORK_TEMPLATE, template) + } + + val scenario = launchFragment(initialState = Lifecycle.State.CREATED) + + scenario.withFragment { + assertThat(findPreference(KEY_WARNING)!!.summary) + .isEqualTo(context.getString(R.string.non_carrier_data_usage_warning)) + } + } + + @Test + fun warning_wifiAndNoSim_noWarning() { + val template = NetworkTemplate.Builder(NetworkTemplate.MATCH_WIFI).build() + spyResources.stub { + on { getBoolean(R.bool.config_show_sim_info) } doReturn false + } + fakeIntent = Intent().apply { + putExtra(Settings.EXTRA_NETWORK_TEMPLATE, template) + } + + val scenario = launchFragment(initialState = Lifecycle.State.CREATED) + + scenario.withFragment { + assertThat(findPreference(KEY_WARNING)!!.summary).isNull() + } + } + + @Test + fun warning_mobile_operatorWarning() { + val template = NetworkTemplate.Builder(NetworkTemplate.MATCH_MOBILE).build() + fakeIntent = Intent().apply { + putExtra(Settings.EXTRA_NETWORK_TEMPLATE, template) + } + + val scenario = launchFragment(initialState = Lifecycle.State.CREATED) + + scenario.withFragment { + assertThat(findPreference(KEY_WARNING)!!.summary) + .isEqualTo(context.getString(R.string.operator_warning)) + } + } } class TestDataUsageList : DataUsageList() { - override fun getContext() = mockContext + override fun getContext() = spyContext override fun getIntent() = fakeIntent } diff --git a/tests/unit/src/com/android/settings/wifi/AddNetworkFragmentTest.java b/tests/unit/src/com/android/settings/wifi/AddNetworkFragmentTest.java new file mode 100644 index 00000000000..22d43c9bb4e --- /dev/null +++ b/tests/unit/src/com/android/settings/wifi/AddNetworkFragmentTest.java @@ -0,0 +1,74 @@ +/* + * 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.wifi; + +import static android.os.UserManager.DISALLOW_ADD_WIFI_CONFIG; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.UserManager; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +@RunWith(AndroidJUnit4.class) +@UiThreadTest +public class AddNetworkFragmentTest { + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + private UserManager mUserManager; + + private AddNetworkFragment mFragment; + + @Before + public void setUp() { + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); + + mFragment = new AddNetworkFragment(); + } + + @Test + public void isAddWifiConfigAllowed_hasNoUserRestriction_returnTrue() { + when(mUserManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)).thenReturn(false); + + assertThat(mFragment.isAddWifiConfigAllowed(mContext)).isTrue(); + } + + @Test + public void isAddWifiConfigAllowed_hasUserRestriction_returnFalse() { + when(mUserManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)).thenReturn(true); + + assertThat(mFragment.isAddWifiConfigAllowed(mContext)).isFalse(); + } +} diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java new file mode 100644 index 00000000000..4d723dc1846 --- /dev/null +++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiDppConfiguratorActivityTest.java @@ -0,0 +1,74 @@ +/* + * 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.wifi.dpp; + +import static android.os.UserManager.DISALLOW_ADD_WIFI_CONFIG; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.os.UserManager; + +import androidx.test.annotation.UiThreadTest; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +@RunWith(AndroidJUnit4.class) +@UiThreadTest +public class WifiDppConfiguratorActivityTest { + + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + @Spy + private final Context mContext = ApplicationProvider.getApplicationContext(); + @Mock + private UserManager mUserManager; + + private WifiDppConfiguratorActivity mActivity; + + @Before + public void setUp() { + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); + + mActivity = new WifiDppConfiguratorActivity(); + } + + @Test + public void isAddWifiConfigAllowed_hasNoUserRestriction_returnTrue() { + when(mUserManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)).thenReturn(false); + + assertThat(mActivity.isAddWifiConfigAllowed(mContext)).isTrue(); + } + + @Test + public void isAddWifiConfigAllowed_hasUserRestriction_returnFalse() { + when(mUserManager.hasUserRestriction(DISALLOW_ADD_WIFI_CONFIG)).thenReturn(true); + + assertThat(mActivity.isAddWifiConfigAllowed(mContext)).isFalse(); + } +} diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java deleted file mode 100644 index e3a8ca5646f..00000000000 --- a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2023 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.wifi.dpp; - -import static com.google.common.truth.Truth.assertThat; - -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -@RunWith(AndroidJUnit4.class) -public class WifiQrCodeTest { - @Test - public void testZxParsing_validCode() { - WifiNetworkConfig config = new WifiQrCode("WIFI:S:testAbC;T:nopass").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("testAbC"); - assertThat(config.getSecurity()).isEqualTo("nopass"); - - config = new WifiQrCode( - "WIFI:S:reallyLONGone;T:WEP;P:somepasswo#%^**123rd").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("reallyLONGone"); - assertThat(config.getSecurity()).isEqualTo("WEP"); - assertThat(config.getPreSharedKey()).isEqualTo("somepasswo#%^**123rd"); - - config = new WifiQrCode("WIFI:S:anotherone;T:WPA;P:3#=3j9asicla").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("anotherone"); - assertThat(config.getSecurity()).isEqualTo("WPA"); - assertThat(config.getPreSharedKey()).isEqualTo("3#=3j9asicla"); - - config = new WifiQrCode("WIFI:S:xx;T:SAE;P:a").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("xx"); - assertThat(config.getSecurity()).isEqualTo("SAE"); - assertThat(config.getPreSharedKey()).isEqualTo("a"); - } - - @Test - public void testZxParsing_invalidCodeButShouldWork() { - WifiNetworkConfig config = new WifiQrCode( - "WIFI:S:testAbC; T:nopass").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("testAbC"); - assertThat(config.getSecurity()).isEqualTo("nopass"); - - config = new WifiQrCode( - "WIFI:S:reallyLONGone;T:WEP; P:somepassword").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("reallyLONGone"); - assertThat(config.getSecurity()).isEqualTo("WEP"); - assertThat(config.getPreSharedKey()).isEqualTo("somepassword"); - - config = new WifiQrCode("WIFI: S:anotherone;T:WPA;P:abcdefghihklmn").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("anotherone"); - assertThat(config.getSecurity()).isEqualTo("WPA"); - assertThat(config.getPreSharedKey()).isEqualTo("abcdefghihklmn"); - - config = new WifiQrCode("WIFI: S:xx; T:SAE; P:a").getWifiNetworkConfig(); - assertThat(config.getSsid()).isEqualTo("xx"); - assertThat(config.getSecurity()).isEqualTo("SAE"); - assertThat(config.getPreSharedKey()).isEqualTo("a"); - } -}