Snap for 11270238 from 0612c9b103 to 24Q2-release

Change-Id: I53ef600f3d77b347fac82749c8b95d1f7af54381
This commit is contained in:
Android Build Coastguard Worker
2024-01-04 00:21:33 +00:00
29 changed files with 692 additions and 396 deletions

View File

@@ -20,3 +20,10 @@ flag {
description: "Gates whether to enable LE audio private broadcast sharing via QR code"
bug: "308368124"
}
flag {
name: "enable_auth_challenge_for_usb_preferences"
namespace: "safety_center"
description: "Gates whether to require an auth challenge for changing USB preferences"
bug: "317367746"
}

View File

@@ -88,6 +88,11 @@
<string name="selective_stay_awake_title">Only games, videos, and more</string>
<!-- Summary for selective stay awake radio button. [CHAR_LIMIT=NONE] -->
<string name="selective_stay_awake_summary">Front display turns on for apps that stop your screen going idle</string>
<!-- Title for fold grace period radio button that, on fold, goes to the lockscreen. [CHAR_LIMIT=NONE] -->
<string name="stay_awake_on_lockscreen_title">Swipe up to continue</string>
<!-- Summary for folding grace period radio button that, on fold, goes to the lockscreen. [CHAR_LIMIT=NONE] -->
<string name="stay_awake_on_lockscreen_summary">Fold your phone and swipe up on the front display to continue using the app, or wait a few seconds for the screen to lock</string>
<!-- Title for sleep on fold radio button. [CHAR_LIMIT=NONE] -->
<string name="sleep_on_fold_title">Never</string>
<!-- Summary for sleep on fold radio button. [CHAR_LIMIT=NONE] -->
@@ -2659,7 +2664,7 @@
<string name="display_white_balance_summary"></string>
<!-- Display settings screen, setting option name to change Fold setting -->
<string name="fold_lock_behavior_title">Continue using apps on fold</string>
<!-- Display settings screen, game default frame rate settings title [CHAR LIMIT=30] -->
<!-- Display settings screen, game default frame rate settings title [CHAR LIMIT=65] -->
<string name="disable_game_default_frame_rate_title">Disable default frame rate for games</string>
<!-- Display settings screen, game default frame rate settings summary [CHAR LIMIT=NONE] -->
<string name="disable_game_default_frame_rate_summary">Disable limiting the maximum frame rate for games at <xliff:g id="frame_rate" example="60">%1$d</xliff:g> Hz.</string>
@@ -8207,6 +8212,9 @@
<!-- a11y string -->
<string name="clear">Clear</string>
<!-- a11y string -->
<string name="clear_conversation">Clear <xliff:g id="conversation_name" example="Mom">%1$s</xliff:g></string>
<!-- title for conversation onboarding -->
<string name="conversation_onboarding_title">Priority and modified conversations will appear here</string>
@@ -9494,7 +9502,7 @@
other {# apps used memory in the last {time}}
}</string>
<!-- Label for toggle that enables the profiling/aggregating of memory usage [CHAR LIMIT=40]-->
<!-- Label for toggle that enables the profiling/aggregating of memory usage [CHAR LIMIT=80]-->
<string name="force_enable_pss_profiling_title">Enable memory usage profiling</string>
<!-- Description with an explanation of the extra resources used if profiling of memory usage is enabled [CHAR LIMIT=NONE]-->
<string name="force_enable_pss_profiling_summary">Memory usage profiling requires additional system resources.</string>

View File

@@ -23,6 +23,8 @@ import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.flags.Flags;
import com.android.settings.wifi.dpp.WifiDppUtils;
import com.android.settingslib.core.AbstractPreferenceController;
/**
@@ -61,4 +63,16 @@ public abstract class UsbDetailsController extends AbstractPreferenceController
*/
@UiThread
protected abstract void refresh(boolean connected, long functions, int powerRole, int dataRole);
/** Protects given action with an auth challenge. */
protected final void requireAuthAndExecute(Runnable action) {
if (Flags.enableAuthChallengeForUsbPreferences() && !mFragment.isUserAuthenticated()) {
WifiDppUtils.showLockScreen(mContext, () -> {
mFragment.setUserAuthenticated(true);
action.run();
});
} else {
action.run();
}
}
}

View File

@@ -98,17 +98,19 @@ public class UsbDetailsDataRoleController extends UsbDetailsController
@Override
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
int role = UsbBackend.dataRoleFromString(preference.getKey());
if (role != mUsbBackend.getDataRole() && mNextRolePref == null
&& !Utils.isMonkeyRunning()) {
mUsbBackend.setDataRole(role);
mNextRolePref = preference;
preference.setSummary(R.string.usb_switching);
requireAuthAndExecute(() -> {
int role = UsbBackend.dataRoleFromString(preference.getKey());
if (role != mUsbBackend.getDataRole() && mNextRolePref == null
&& !Utils.isMonkeyRunning()) {
mUsbBackend.setDataRole(role);
mNextRolePref = preference;
preference.setSummary(R.string.usb_switching);
mHandler.postDelayed(mFailureCallback,
mUsbBackend.areAllRolesSupported() ? UsbBackend.PD_ROLE_SWAP_TIMEOUT_MS
: UsbBackend.NONPD_ROLE_SWAP_TIMEOUT_MS);
}
mHandler.postDelayed(mFailureCallback,
mUsbBackend.areAllRolesSupported() ? UsbBackend.PD_ROLE_SWAP_TIMEOUT_MS
: UsbBackend.NONPD_ROLE_SWAP_TIMEOUT_MS);
}
});
}
@Override

View File

@@ -45,6 +45,7 @@ public class UsbDetailsFragment extends DashboardFragment {
private List<UsbDetailsController> mControllers;
private UsbBackend mUsbBackend;
private boolean mUserAuthenticated = false;
@VisibleForTesting
UsbConnectionBroadcastReceiver mUsbReceiver;
@@ -56,6 +57,20 @@ public class UsbDetailsFragment extends DashboardFragment {
}
};
boolean isUserAuthenticated() {
return mUserAuthenticated;
}
void setUserAuthenticated(boolean userAuthenticated) {
mUserAuthenticated = userAuthenticated;
}
@Override
public void onStart() {
super.onStart();
mUserAuthenticated = false;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);

View File

@@ -130,37 +130,39 @@ public class UsbDetailsFunctionsController extends UsbDetailsController
@Override
public void onRadioButtonClicked(SelectorWithWidgetPreference preference) {
final long function = UsbBackend.usbFunctionsFromString(preference.getKey());
final long previousFunction = mUsbBackend.getCurrentFunctions();
if (DEBUG) {
Log.d(TAG, "onRadioButtonClicked() function : " + function + ", toString() : "
+ UsbManager.usbFunctionsToString(function) + ", previousFunction : "
+ previousFunction + ", toString() : "
+ UsbManager.usbFunctionsToString(previousFunction));
}
if (function != previousFunction && !Utils.isMonkeyRunning()
&& !isClickEventIgnored(function, previousFunction)) {
mPreviousFunction = previousFunction;
//Update the UI in advance to make it looks smooth
final SelectorWithWidgetPreference prevPref =
(SelectorWithWidgetPreference) mProfilesContainer.findPreference(
UsbBackend.usbFunctionsToString(mPreviousFunction));
if (prevPref != null) {
prevPref.setChecked(false);
preference.setChecked(true);
requireAuthAndExecute(() -> {
final long function = UsbBackend.usbFunctionsFromString(preference.getKey());
final long previousFunction = mUsbBackend.getCurrentFunctions();
if (DEBUG) {
Log.d(TAG, "onRadioButtonClicked() function : " + function + ", toString() : "
+ UsbManager.usbFunctionsToString(function) + ", previousFunction : "
+ previousFunction + ", toString() : "
+ UsbManager.usbFunctionsToString(previousFunction));
}
if (function != previousFunction && !Utils.isMonkeyRunning()
&& !isClickEventIgnored(function, previousFunction)) {
mPreviousFunction = previousFunction;
if (function == UsbManager.FUNCTION_RNDIS || function == UsbManager.FUNCTION_NCM) {
// We need to have entitlement check for usb tethering, so use API in
// TetheringManager.
mTetheringManager.startTethering(
TetheringManager.TETHERING_USB, new HandlerExecutor(mHandler),
mOnStartTetheringCallback);
} else {
mUsbBackend.setCurrentFunctions(function);
//Update the UI in advance to make it looks smooth
final SelectorWithWidgetPreference prevPref =
(SelectorWithWidgetPreference) mProfilesContainer.findPreference(
UsbBackend.usbFunctionsToString(mPreviousFunction));
if (prevPref != null) {
prevPref.setChecked(false);
preference.setChecked(true);
}
if (function == UsbManager.FUNCTION_RNDIS || function == UsbManager.FUNCTION_NCM) {
// We need to have entitlement check for usb tethering, so use API in
// TetheringManager.
mTetheringManager.startTethering(
TetheringManager.TETHERING_USB, new HandlerExecutor(mHandler),
mOnStartTetheringCallback);
} else {
mUsbBackend.setCurrentFunctions(function);
}
}
}
});
}
private boolean isClickEventIgnored(long function, long previousFunction) {

View File

@@ -78,13 +78,15 @@ public class UsbDetailsTranscodeMtpController extends UsbDetailsController
@Override
public boolean onPreferenceClick(Preference preference) {
SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY,
Boolean.toString(mSwitchPreference.isChecked()));
requireAuthAndExecute(() -> {
SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY,
Boolean.toString(mSwitchPreference.isChecked()));
final long previousFunctions = mUsbBackend.getCurrentFunctions();
// Toggle the MTP connection to reload file sizes for files shared via MTP clients
mUsbBackend.setCurrentFunctions(previousFunctions & ~UsbManager.FUNCTION_MTP);
mUsbBackend.setCurrentFunctions(previousFunctions);
final long previousFunctions = mUsbBackend.getCurrentFunctions();
// Toggle the MTP connection to reload file sizes for files shared via MTP clients
mUsbBackend.setCurrentFunctions(previousFunctions & ~UsbManager.FUNCTION_MTP);
mUsbBackend.setCurrentFunctions(previousFunctions);
});
return true;
}

View File

@@ -29,6 +29,7 @@ import android.provider.Settings;
import androidx.preference.Preference;
import com.android.internal.foldables.FoldGracePeriodProvider;
import com.android.internal.foldables.FoldLockSettingAvailabilityProvider;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -58,8 +59,13 @@ public class FoldLockBehaviorPreferenceController extends BasePreferenceControll
mFoldLockSettingAvailabilityProvider = foldLockSettingAvailabilityProvider;
KEY_TO_TEXT.put(SETTING_VALUE_STAY_AWAKE_ON_FOLD,
resourceToString(R.string.stay_awake_on_fold_title));
KEY_TO_TEXT.put(SETTING_VALUE_SELECTIVE_STAY_AWAKE,
resourceToString(R.string.selective_stay_awake_title));
if (new FoldGracePeriodProvider().isEnabled()) {
KEY_TO_TEXT.put(SETTING_VALUE_SELECTIVE_STAY_AWAKE,
resourceToString(R.string.stay_awake_on_lockscreen_title));
} else {
KEY_TO_TEXT.put(SETTING_VALUE_SELECTIVE_STAY_AWAKE,
resourceToString(R.string.selective_stay_awake_title));
}
KEY_TO_TEXT.put(SETTING_VALUE_SLEEP_ON_FOLD,
resourceToString(R.string.sleep_on_fold_title));
}

View File

@@ -24,6 +24,7 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import com.android.internal.foldables.FoldGracePeriodProvider;
import com.android.settings.R;
import com.android.settings.support.actionbar.HelpResourceProvider;
import com.android.settings.utils.CandidateInfoExtra;
@@ -54,6 +55,7 @@ public class FoldLockBehaviorSettings extends RadioButtonPickerFragment implemen
SETTING_VALUE_SLEEP_ON_FOLD));
private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE;
private Context mContext;
private final FoldGracePeriodProvider mFoldGracePeriodProvider = new FoldGracePeriodProvider();
@Override
public void onAttach(Context context) {
@@ -69,10 +71,17 @@ public class FoldLockBehaviorSettings extends RadioButtonPickerFragment implemen
resourceToString(R.string.stay_awake_on_fold_title),
resourceToString(R.string.stay_awake_on_fold_summary),
SETTING_VALUE_STAY_AWAKE_ON_FOLD, /* enabled */ true));
candidates.add(new CandidateInfoExtra(
resourceToString(R.string.selective_stay_awake_title),
resourceToString(R.string.selective_stay_awake_summary),
SETTING_VALUE_SELECTIVE_STAY_AWAKE, /* enabled */ true));
if (mFoldGracePeriodProvider.isEnabled()) {
candidates.add(new CandidateInfoExtra(
resourceToString(R.string.stay_awake_on_lockscreen_title),
resourceToString(R.string.stay_awake_on_lockscreen_summary),
SETTING_VALUE_SELECTIVE_STAY_AWAKE, /* enabled */ true));
} else {
candidates.add(new CandidateInfoExtra(
resourceToString(R.string.selective_stay_awake_title),
resourceToString(R.string.selective_stay_awake_summary),
SETTING_VALUE_SELECTIVE_STAY_AWAKE, /* enabled */ true));
}
candidates.add(new CandidateInfoExtra(
resourceToString(R.string.sleep_on_fold_title),
resourceToString(R.string.sleep_on_fold_summary),

View File

@@ -83,17 +83,8 @@ public class BatteryDefenderTip extends BatteryTip {
}
cardPreference.setSelectable(false);
cardPreference.setPrimaryButtonText(
context.getString(R.string.battery_tip_charge_to_full_button));
cardPreference.setPrimaryButtonText(context.getString(R.string.learn_more));
cardPreference.setPrimaryButtonClickListener(
unused -> {
resumeCharging(context);
preference.setVisible(false);
});
cardPreference.setPrimaryButtonVisible(mIsPluggedIn);
cardPreference.setSecondaryButtonText(context.getString(R.string.learn_more));
cardPreference.setSecondaryButtonClickListener(
button ->
button.startActivityForResult(
HelpUtils.getHelpIntent(
@@ -101,10 +92,19 @@ public class BatteryDefenderTip extends BatteryTip {
context.getString(R.string.help_url_battery_defender),
/* backupContext */ ""), /* requestCode */
0));
cardPreference.setSecondaryButtonVisible(true);
cardPreference.setSecondaryButtonContentDescription(
cardPreference.setPrimaryButtonVisible(true);
cardPreference.setPrimaryButtonContentDescription(
context.getString(
R.string.battery_tip_limited_temporarily_sec_button_content_description));
cardPreference.setSecondaryButtonText(
context.getString(R.string.battery_tip_charge_to_full_button));
cardPreference.setSecondaryButtonClickListener(
unused -> {
resumeCharging(context);
preference.setVisible(false);
});
cardPreference.setSecondaryButtonVisible(mIsPluggedIn);
}
private void resumeCharging(Context context) {

View File

@@ -26,7 +26,6 @@ import android.util.Log;
import com.android.settings.core.instrumentation.ElapsedTimeUtils;
import com.android.settings.fuelgauge.BatteryUsageHistoricalLogEntry.Action;
import com.android.settings.fuelgauge.batteryusage.bugreport.BatteryUsageLogUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.fuelgauge.BatteryUtils;
import java.time.Duration;
@@ -34,9 +33,7 @@ import java.time.Duration;
/** Receives broadcasts to start or stop the periodic fetching job. */
public final class BootBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "BootBroadcastReceiver";
private static final long RESCHEDULE_FOR_BOOT_ACTION_WITH_DELAY =
Duration.ofMinutes(40).toMillis();
private static final long RESCHEDULE_FOR_BOOT_ACTION_WITHOUT_DELAY =
private static final long RESCHEDULE_FOR_BOOT_ACTION_DELAY_MILLIS =
Duration.ofSeconds(6).toMillis();
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -81,7 +78,7 @@ public final class BootBroadcastReceiver extends BroadcastReceiver {
if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
final Intent recheckIntent = new Intent(ACTION_PERIODIC_JOB_RECHECK);
recheckIntent.setClass(context, BootBroadcastReceiver.class);
final long delayedTime = getRescheduleTimeForBootAction(context);
final long delayedTime = RESCHEDULE_FOR_BOOT_ACTION_DELAY_MILLIS;
mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), delayedTime);
// Refreshes the usage source from UsageStatsManager when booting.
@@ -93,16 +90,6 @@ public final class BootBroadcastReceiver extends BroadcastReceiver {
}
}
private long getRescheduleTimeForBootAction(Context context) {
final boolean delayHourlyJobWhenBooting =
FeatureFactory.getFeatureFactory()
.getPowerUsageFeatureProvider()
.delayHourlyJobWhenBooting();
return delayHourlyJobWhenBooting
? RESCHEDULE_FOR_BOOT_ACTION_WITH_DELAY
: RESCHEDULE_FOR_BOOT_ACTION_WITHOUT_DELAY;
}
private static void refreshJobs(Context context) {
PeriodicJobManager.getInstance(context).refreshJob(/* fromBoot= */ true);
}

View File

@@ -158,13 +158,14 @@ public class AppLocalePickerActivity extends SettingsBaseActivity
private void broadcastAppLocaleChange(LocaleStore.LocaleInfo localeInfo) {
if (!localeNotificationEnabled()) {
Log.w(TAG, "Locale notification is not enabled");
return;
}
String localeTag = localeInfo.getLocale().toLanguageTag();
if (LocaleUtils.isInSystemLocale(localeTag) || localeInfo.isAppCurrentLocale()) {
if (localeInfo.isAppCurrentLocale()) {
return;
}
try {
String localeTag = localeInfo.getLocale().toLanguageTag();
int uid = getPackageManager().getApplicationInfo(mPackageName,
PackageManager.GET_META_DATA).uid;
boolean launchNotification = mNotificationController.shouldTriggerNotification(

View File

@@ -270,12 +270,14 @@ class LocaleDragAndDropAdapter
void removeChecked() {
int itemCount = mFeedItemList.size();
LocaleStore.LocaleInfo localeInfo;
NotificationController controller = NotificationController.getInstance(mContext);
for (int i = itemCount - 1; i >= 0; i--) {
localeInfo = mFeedItemList.get(i);
if (localeInfo.getChecked()) {
FeatureFactory.getFeatureFactory().getMetricsFeatureProvider()
.action(mContext, SettingsEnums.ACTION_REMOVE_LANGUAGE);
mFeedItemList.remove(i);
controller.removeNotificationInfo(localeInfo.getLocale().toLanguageTag());
}
}
notifyDataSetChanged();

View File

@@ -62,6 +62,17 @@ public class LocaleNotificationDataManager {
editor.apply();
}
/**
* Removes one entry with the corresponding locale from the {@link SharedPreferences}.
*
* @param locale A locale which the application sets to
*/
public void removeNotificationInfo(String locale) {
SharedPreferences.Editor editor = getSharedPreferences(mContext).edit();
editor.remove(locale);
editor.apply();
}
/**
* Gets the {@link NotificationInfo} with the associated locale from the
* {@link SharedPreferences}.

View File

@@ -110,6 +110,15 @@ public class NotificationController {
return (info != null) ? info.getNotificationId() : -1;
}
/**
* Remove the {@link NotificationInfo} with the corresponding locale
*
* @param locale The locale which the application sets to
*/
public void removeNotificationInfo(@NonNull String locale) {
mDataManager.removeNotificationInfo(locale);
}
private boolean updateLocaleNotificationInfo(int uid, String locale) {
NotificationInfo info = mDataManager.getNotificationInfo(locale);
if (info == null) {
@@ -135,20 +144,20 @@ public class NotificationController {
int notificationCount = info.getNotificationCount();
long lastNotificationTime = info.getLastNotificationTimeMs();
int notificationId = info.getNotificationId();
// Add the uid into the locale's uid list
uidSet.add(uid);
if (dismissCount < DISMISS_COUNT_THRESHOLD
&& notificationCount < NOTIFICATION_COUNT_THRESHOLD
// Notification should fire on multiples of 2 apps using the locale.
&& uidSet.size() % MULTIPLE_BASE == 0
&& !isNotificationFrequent(lastNotificationTime)) {
// Increment the count because the notification can be triggered.
notificationCount = info.getNotificationCount() + 1;
lastNotificationTime = Calendar.getInstance().getTimeInMillis();
Log.i(TAG, "notificationCount:" + notificationCount);
if (notificationCount == 1) {
notificationId = (int) SystemClock.uptimeMillis();
&& notificationCount < NOTIFICATION_COUNT_THRESHOLD) {
// Add the uid into the locale's uid list
uidSet.add(uid);
// Notification should fire on multiples of 2 apps using the locale.
if (uidSet.size() % MULTIPLE_BASE == 0
&& !isNotificationFrequent(lastNotificationTime)) {
// Increment the count because the notification can be triggered.
notificationCount = info.getNotificationCount() + 1;
lastNotificationTime = Calendar.getInstance().getTimeInMillis();
Log.i(TAG, "notificationCount:" + notificationCount);
if (notificationCount == 1) {
notificationId = (int) SystemClock.uptimeMillis();
}
}
}
return new NotificationInfo(uidSet, notificationCount, dismissCount, lastNotificationTime,

View File

@@ -1,219 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.network.telephony;
import android.telephony.CellIdentity;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityNr;
import android.telephony.CellIdentityTdscdma;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoNr;
import android.telephony.CellInfoTdscdma;
import android.telephony.CellInfoWcdma;
import android.text.BidiFormatter;
import android.text.TextDirectionHeuristics;
import android.text.TextUtils;
import com.android.internal.telephony.OperatorInfo;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* Add static Utility functions to get information from the CellInfo object.
* TODO: Modify {@link CellInfo} for simplify those functions
*/
public final class CellInfoUtil {
private static final String TAG = "NetworkSelectSetting";
private CellInfoUtil() {
}
/**
* Returns the title of the network obtained in the manual search.
*
* @param cellId contains the identity of the network.
* @param networkMccMnc contains the MCCMNC string of the network
* @return Long Name if not null/empty, otherwise Short Name if not null/empty,
* else MCCMNC string.
*/
public static String getNetworkTitle(CellIdentity cellId, String networkMccMnc) {
if (cellId != null) {
String title = Objects.toString(cellId.getOperatorAlphaLong(), "");
if (TextUtils.isEmpty(title)) {
title = Objects.toString(cellId.getOperatorAlphaShort(), "");
}
if (!TextUtils.isEmpty(title)) {
return title;
}
}
if (TextUtils.isEmpty(networkMccMnc)) {
return "";
}
final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
return bidiFormatter.unicodeWrap(networkMccMnc, TextDirectionHeuristics.LTR);
}
/**
* Returns the CellIdentity from CellInfo
*
* @param cellInfo contains the information of the network.
* @return CellIdentity within CellInfo
*/
public static CellIdentity getCellIdentity(CellInfo cellInfo) {
if (cellInfo == null) {
return null;
}
CellIdentity cellId = null;
if (cellInfo instanceof CellInfoGsm) {
cellId = ((CellInfoGsm) cellInfo).getCellIdentity();
} else if (cellInfo instanceof CellInfoCdma) {
cellId = ((CellInfoCdma) cellInfo).getCellIdentity();
} else if (cellInfo instanceof CellInfoWcdma) {
cellId = ((CellInfoWcdma) cellInfo).getCellIdentity();
} else if (cellInfo instanceof CellInfoTdscdma) {
cellId = ((CellInfoTdscdma) cellInfo).getCellIdentity();
} else if (cellInfo instanceof CellInfoLte) {
cellId = ((CellInfoLte) cellInfo).getCellIdentity();
} else if (cellInfo instanceof CellInfoNr) {
cellId = ((CellInfoNr) cellInfo).getCellIdentity();
}
return cellId;
}
/**
* Creates a CellInfo object from OperatorInfo. GsmCellInfo is used here only because
* operatorInfo does not contain technology type while CellInfo is an abstract object that
* requires to specify technology type. It doesn't matter which CellInfo type to use here, since
* we only want to wrap the operator info and PLMN to a CellInfo object.
*/
public static CellInfo convertOperatorInfoToCellInfo(OperatorInfo operatorInfo) {
final String operatorNumeric = operatorInfo.getOperatorNumeric();
String mcc = null;
String mnc = null;
if (operatorNumeric != null && operatorNumeric.matches("^[0-9]{5,6}$")) {
mcc = operatorNumeric.substring(0, 3);
mnc = operatorNumeric.substring(3);
}
final CellIdentityGsm cig = new CellIdentityGsm(
Integer.MAX_VALUE /* lac */,
Integer.MAX_VALUE /* cid */,
Integer.MAX_VALUE /* arfcn */,
Integer.MAX_VALUE /* bsic */,
mcc,
mnc,
operatorInfo.getOperatorAlphaLong(),
operatorInfo.getOperatorAlphaShort(),
Collections.emptyList());
final CellInfoGsm ci = new CellInfoGsm();
ci.setCellIdentity(cig);
return ci;
}
/** Convert a list of cellInfos to readable string without sensitive info. */
public static String cellInfoListToString(List<CellInfo> cellInfos) {
return cellInfos.stream()
.map(cellInfo -> cellInfoToString(cellInfo))
.collect(Collectors.joining(", "));
}
/** Convert {@code cellInfo} to a readable string without sensitive info. */
public static String cellInfoToString(CellInfo cellInfo) {
final String cellType = cellInfo.getClass().getSimpleName();
final CellIdentity cid = getCellIdentity(cellInfo);
String mcc = getCellIdentityMcc(cid);
String mnc = getCellIdentityMnc(cid);
CharSequence alphaLong = null;
CharSequence alphaShort = null;
if (cid != null) {
alphaLong = cid.getOperatorAlphaLong();
alphaShort = cid.getOperatorAlphaShort();
}
return String.format(
"{CellType = %s, isRegistered = %b, mcc = %s, mnc = %s, alphaL = %s, alphaS = %s}",
cellType, cellInfo.isRegistered(), mcc, mnc,
alphaLong, alphaShort);
}
/**
* Returns the MccMnc.
*
* @param cid contains the identity of the network.
* @return MccMnc string.
*/
public static String getCellIdentityMccMnc(CellIdentity cid) {
String mcc = getCellIdentityMcc(cid);
String mnc = getCellIdentityMnc(cid);
return (mcc == null || mnc == null) ? null : mcc + mnc;
}
/**
* Returns the Mcc.
*
* @param cid contains the identity of the network.
* @return Mcc string.
*/
public static String getCellIdentityMcc(CellIdentity cid) {
String mcc = null;
if (cid != null) {
if (cid instanceof CellIdentityGsm) {
mcc = ((CellIdentityGsm) cid).getMccString();
} else if (cid instanceof CellIdentityWcdma) {
mcc = ((CellIdentityWcdma) cid).getMccString();
} else if (cid instanceof CellIdentityTdscdma) {
mcc = ((CellIdentityTdscdma) cid).getMccString();
} else if (cid instanceof CellIdentityLte) {
mcc = ((CellIdentityLte) cid).getMccString();
} else if (cid instanceof CellIdentityNr) {
mcc = ((CellIdentityNr) cid).getMccString();
}
}
return (mcc == null) ? null : mcc;
}
/**
* Returns the Mnc.
*
* @param cid contains the identity of the network.
* @return Mcc string.
*/
public static String getCellIdentityMnc(CellIdentity cid) {
String mnc = null;
if (cid != null) {
if (cid instanceof CellIdentityGsm) {
mnc = ((CellIdentityGsm) cid).getMncString();
} else if (cid instanceof CellIdentityWcdma) {
mnc = ((CellIdentityWcdma) cid).getMncString();
} else if (cid instanceof CellIdentityTdscdma) {
mnc = ((CellIdentityTdscdma) cid).getMncString();
} else if (cid instanceof CellIdentityLte) {
mnc = ((CellIdentityLte) cid).getMncString();
} else if (cid instanceof CellIdentityNr) {
mnc = ((CellIdentityNr) cid).getMncString();
}
}
return (mnc == null) ? null : mnc;
}
}

View File

@@ -0,0 +1,113 @@
/*
* 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.network.telephony
import android.telephony.CellIdentity
import android.telephony.CellIdentityGsm
import android.telephony.CellInfo
import android.telephony.CellInfoGsm
import android.text.BidiFormatter
import android.text.TextDirectionHeuristics
import com.android.internal.telephony.OperatorInfo
/**
* Add static Utility functions to get information from the CellInfo object.
* TODO: Modify [CellInfo] for simplify those functions
*/
object CellInfoUtil {
/**
* Returns the title of the network obtained in the manual search.
*
* By the following order,
* 1. Long Name if not null/empty
* 2. Short Name if not null/empty
* 3. OperatorNumeric (MCCMNC) string
*/
@JvmStatic
fun CellIdentity.getNetworkTitle(): String? {
operatorAlphaLong?.takeIf { it.isNotBlank() }?.let { return it.toString() }
operatorAlphaShort?.takeIf { it.isNotBlank() }?.let { return it.toString() }
val operatorNumeric = getOperatorNumeric() ?: return null
val bidiFormatter = BidiFormatter.getInstance()
return bidiFormatter.unicodeWrap(operatorNumeric, TextDirectionHeuristics.LTR)
}
/**
* Creates a CellInfo object from OperatorInfo. GsmCellInfo is used here only because
* operatorInfo does not contain technology type while CellInfo is an abstract object that
* requires to specify technology type. It doesn't matter which CellInfo type to use here, since
* we only want to wrap the operator info and PLMN to a CellInfo object.
*/
@JvmStatic
fun convertOperatorInfoToCellInfo(operatorInfo: OperatorInfo): CellInfo {
val operatorNumeric = operatorInfo.operatorNumeric
var mcc: String? = null
var mnc: String? = null
if (operatorNumeric?.matches("^[0-9]{5,6}$".toRegex()) == true) {
mcc = operatorNumeric.substring(0, 3)
mnc = operatorNumeric.substring(3)
}
return CellInfoGsm().apply {
cellIdentity = CellIdentityGsm(
/* lac = */ Int.MAX_VALUE,
/* cid = */ Int.MAX_VALUE,
/* arfcn = */ Int.MAX_VALUE,
/* bsic = */ Int.MAX_VALUE,
/* mccStr = */ mcc,
/* mncStr = */ mnc,
/* alphal = */ operatorInfo.operatorAlphaLong,
/* alphas = */ operatorInfo.operatorAlphaShort,
/* additionalPlmns = */ emptyList(),
)
}
}
/**
* Convert a list of cellInfos to readable string without sensitive info.
*/
@JvmStatic
fun cellInfoListToString(cellInfos: List<CellInfo>): String =
cellInfos.joinToString { cellInfo -> cellInfo.readableString() }
/**
* Convert [CellInfo] to a readable string without sensitive info.
*/
private fun CellInfo.readableString(): String = buildString {
append("{CellType = ${this@readableString::class.simpleName}, ")
append("isRegistered = $isRegistered, ")
append(cellIdentity.readableString())
append("}")
}
private fun CellIdentity.readableString(): String = buildString {
append("mcc = $mccString, ")
append("mnc = $mncString, ")
append("alphaL = $operatorAlphaLong, ")
append("alphaS = $operatorAlphaShort")
}
/**
* Returns the MccMnc.
*/
@JvmStatic
fun CellIdentity.getOperatorNumeric(): String? {
val mcc = mccString
val mnc = mncString
return if (mcc == null || mnc == null) null else mcc + mnc
}
}

View File

@@ -18,14 +18,11 @@ package com.android.settings.network.telephony;
import static android.telephony.SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
import static com.android.settings.network.telephony.CellInfoUtil.getOperatorNumeric;
import android.content.Context;
import android.telephony.AccessNetworkConstants.AccessNetworkType;
import android.telephony.CellIdentity;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityNr;
import android.telephony.CellIdentityTdscdma;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
@@ -36,6 +33,7 @@ import android.telephony.CellInfoWcdma;
import android.telephony.CellSignalStrength;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -87,7 +85,7 @@ public class NetworkOperatorPreference extends Preference {
* Change cell information
*/
public void updateCell(CellInfo cellinfo) {
updateCell(cellinfo, CellInfoUtil.getCellIdentity(cellinfo));
updateCell(cellinfo, cellinfo.getCellIdentity());
}
@VisibleForTesting
@@ -104,14 +102,14 @@ public class NetworkOperatorPreference extends Preference {
if (cellinfo == null) {
return false;
}
return mCellId.equals(CellInfoUtil.getCellIdentity(cellinfo));
return mCellId.equals(cellinfo.getCellIdentity());
}
/**
* Return true when this preference is for forbidden network
*/
public boolean isForbiddenNetwork() {
return ((mForbiddenPlmns != null) && mForbiddenPlmns.contains(getOperatorNumeric()));
return ((mForbiddenPlmns != null) && mForbiddenPlmns.contains(getOperatorNumeric(mCellId)));
}
/**
@@ -147,41 +145,12 @@ public class NetworkOperatorPreference extends Preference {
updateIcon(level);
}
/**
* Operator numeric of this cell
*/
public String getOperatorNumeric() {
final CellIdentity cellId = mCellId;
if (cellId == null) {
return null;
}
if (cellId instanceof CellIdentityGsm) {
return ((CellIdentityGsm) cellId).getMobileNetworkOperator();
}
if (cellId instanceof CellIdentityWcdma) {
return ((CellIdentityWcdma) cellId).getMobileNetworkOperator();
}
if (cellId instanceof CellIdentityTdscdma) {
return ((CellIdentityTdscdma) cellId).getMobileNetworkOperator();
}
if (cellId instanceof CellIdentityLte) {
return ((CellIdentityLte) cellId).getMobileNetworkOperator();
}
if (cellId instanceof CellIdentityNr) {
final String mcc = ((CellIdentityNr) cellId).getMccString();
if (mcc == null) {
return null;
}
return mcc.concat(((CellIdentityNr) cellId).getMncString());
}
return null;
}
/**
* Operator name of this cell
*/
@Nullable
public String getOperatorName() {
return CellInfoUtil.getNetworkTitle(mCellId, getOperatorNumeric());
return CellInfoUtil.getNetworkTitle(mCellId);
}
/**
@@ -190,7 +159,7 @@ public class NetworkOperatorPreference extends Preference {
public OperatorInfo getOperatorInfo() {
return new OperatorInfo(Objects.toString(mCellId.getOperatorAlphaLong(), ""),
Objects.toString(mCellId.getOperatorAlphaShort(), ""),
getOperatorNumeric(), getAccessNetworkTypeFromCellInfo(mCellInfo));
getOperatorNumeric(mCellId), getAccessNetworkTypeFromCellInfo(mCellInfo));
}
private int getIconIdForCell(CellInfo ci) {

View File

@@ -365,14 +365,12 @@ public class NetworkSelectSettings extends DashboardFragment {
}
ArrayList<CellInfo> aggregatedList = new ArrayList<>();
for (CellInfo cellInfo : cellInfoListInput) {
String plmn = CellInfoUtil.getNetworkTitle(cellInfo.getCellIdentity(),
CellInfoUtil.getCellIdentityMccMnc(cellInfo.getCellIdentity()));
String plmn = CellInfoUtil.getNetworkTitle(cellInfo.getCellIdentity());
Class className = cellInfo.getClass();
Optional<CellInfo> itemInTheList = aggregatedList.stream().filter(
item -> {
String itemPlmn = CellInfoUtil.getNetworkTitle(item.getCellIdentity(),
CellInfoUtil.getCellIdentityMccMnc(item.getCellIdentity()));
String itemPlmn = CellInfoUtil.getNetworkTitle(item.getCellIdentity());
return itemPlmn.equals(plmn) && item.getClass().equals(className);
})
.findFirst();

View File

@@ -28,7 +28,7 @@ import com.google.common.annotations.VisibleForTesting;
public class RecentConversationPreference extends TwoTargetPreference {
private OnClearClickListener mOnClearClickListener;
private final Context mContext;
private View mClearView;
public interface OnClearClickListener {
@@ -37,6 +37,7 @@ public class RecentConversationPreference extends TwoTargetPreference {
public RecentConversationPreference(Context context) {
super(context);
mContext = context;
}
public void setOnClearClickListener(
@@ -70,6 +71,9 @@ public class RecentConversationPreference extends TwoTargetPreference {
final View widgetFrame = view.findViewById(android.R.id.widget_frame);
widgetFrame.setVisibility(mOnClearClickListener != null ? View.VISIBLE : View.GONE);
mClearView = view.findViewById(getClearId());
mClearView.setContentDescription(
mContext.getString(R.string.clear_conversation, getTitle()));
mClearView.setOnClickListener(v -> {
if (mOnClearClickListener != null) {
mOnClearClickListener.onClear();

View File

@@ -0,0 +1,113 @@
/*
* 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.connecteddevice.usb;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.verify;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbPortStatus;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import com.android.settings.flags.Flags;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowKeyguardManager;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {
ShadowKeyguardManager.class
})
public class UsbDetailsControllerTest {
@Rule
public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
@Mock
private UsbBackend mUsbBackend;
private Context mContext;
private UsbDetailsController mUsbDetailsController;
private UsbDetailsFragment mUsbDetailsFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = getApplicationContext();
mUsbDetailsFragment = new UsbDetailsFragment();
mUsbDetailsController = new UsbDetailsController(
mContext, mUsbDetailsFragment, mUsbBackend) {
@Override
protected void refresh(boolean connected, long functions, int powerRole, int dataRole) {
}
@Override
public String getPreferenceKey() {
return null;
}
};
}
@Test
public void isAvailable_returnsTrue() {
assertThat(mUsbDetailsController.isAvailable()).isTrue();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void requireAuthAndExecute_whenAlreadyAuthenticated_executes() {
mUsbDetailsFragment.setUserAuthenticated(true);
Runnable action = () -> mUsbBackend.setDataRole(UsbPortStatus.DATA_ROLE_HOST);
mUsbDetailsController.requireAuthAndExecute(action);
verify(mUsbBackend).setDataRole(anyInt());
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void requireAuthAndExecute_authenticatesAndExecutes() {
mUsbDetailsFragment.setUserAuthenticated(false);
setAuthPassesAutomatically();
Runnable action = () -> mUsbBackend.setDataRole(UsbPortStatus.DATA_ROLE_HOST);
mUsbDetailsController.requireAuthAndExecute(action);
assertThat(mUsbDetailsFragment.isUserAuthenticated()).isTrue();
verify(mUsbBackend).setDataRole(anyInt());
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
}

View File

@@ -25,12 +25,15 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
@@ -38,6 +41,7 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.flags.Flags;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
@@ -49,6 +53,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -63,12 +68,11 @@ public class UsbDetailsDataRoleControllerTest {
private PreferenceCategory mPreference;
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
private UsbDetailsFragment mFragment;
@Mock
private UsbBackend mUsbBackend;
@Mock
private UsbDetailsFragment mFragment;
@Mock
private FragmentActivity mActivity;
@Mock
private Handler mHandler;
@@ -76,7 +80,7 @@ public class UsbDetailsDataRoleControllerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new UsbDetailsFragment());
mContext = RuntimeEnvironment.application;
mLifecycle = new Lifecycle(() -> mLifecycle);
mPreferenceManager = new PreferenceManager(mContext);
@@ -95,12 +99,12 @@ public class UsbDetailsDataRoleControllerTest {
mScreen.addPreference(mPreference);
mDetailsDataRoleController.mHandler = mHandler;
mDetailsDataRoleController.displayPreference(mScreen);
}
@Test
public void displayRefresh_deviceRole_shouldCheckDevice() {
mDetailsDataRoleController.displayPreference(mScreen);
mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
DATA_ROLE_DEVICE);
@@ -112,8 +116,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void displayRefresh_hostRole_shouldCheckHost() {
mDetailsDataRoleController.displayPreference(mScreen);
mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
DATA_ROLE_HOST);
@@ -125,8 +127,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void displayRefresh_disconnected_shouldDisable() {
mDetailsDataRoleController.displayPreference(mScreen);
mDetailsDataRoleController.refresh(false, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK,
DATA_ROLE_DEVICE);
@@ -135,7 +135,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDevice_hostEnabled_shouldSetDevice() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -148,7 +147,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDeviceTwice_hostEnabled_shouldSetDeviceOnce() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -162,7 +160,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDeviceAndRefresh_success_shouldClearSubtext() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -180,7 +177,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDeviceAndRefresh_failed_shouldShowFailureText() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -199,7 +195,6 @@ public class UsbDetailsDataRoleControllerTest {
@Test
public void onClickDevice_timedOut_shouldShowFailureText() {
mDetailsDataRoleController.displayPreference(mScreen);
when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST);
final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE);
@@ -218,6 +213,22 @@ public class UsbDetailsDataRoleControllerTest {
.isEqualTo(mContext.getString(R.string.usb_switching_failed));
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void onRadioButtonClicked_userAuthenticated() {
SelectorWithWidgetPreference preference = getRadioPreference(DATA_ROLE_DEVICE);
setAuthPassesAutomatically();
mDetailsDataRoleController.onRadioButtonClicked(preference);
assertThat(mFragment.isUserAuthenticated()).isTrue();
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
private SelectorWithWidgetPreference getRadioPreference(int role) {
return (SelectorWithWidgetPreference)
mPreference.findPreference(UsbBackend.dataRoleToString(role));

View File

@@ -30,15 +30,18 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.net.TetheringManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
@@ -51,6 +54,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
@@ -70,12 +74,11 @@ public class UsbDetailsFunctionsControllerTest {
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
private SelectorWithWidgetPreference mRadioButtonPreference;
private UsbDetailsFragment mFragment;
@Mock
private UsbBackend mUsbBackend;
@Mock
private UsbDetailsFragment mFragment;
@Mock
private FragmentActivity mActivity;
@Mock
private TetheringManager mTetheringManager;
@@ -83,7 +86,7 @@ public class UsbDetailsFunctionsControllerTest {
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new UsbDetailsFragment());
mContext = spy(RuntimeEnvironment.application);
mLifecycle = new Lifecycle(() -> mLifecycle);
mPreferenceManager = new PreferenceManager(mContext);
@@ -334,6 +337,23 @@ public class UsbDetailsFunctionsControllerTest {
eq(mDetailsFunctionsController.mOnStartTetheringCallback));
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void onRadioButtonClicked_userAuthenticated() {
mRadioButtonPreference.setKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_PTP));
doReturn(UsbManager.FUNCTION_MTP).when(mUsbBackend).getCurrentFunctions();
setAuthPassesAutomatically();
mDetailsFunctionsController.onRadioButtonClicked(mRadioButtonPreference);
assertThat(mFragment.isUserAuthenticated()).isTrue();
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
@Test
public void onTetheringFailed_resetPreviousFunctions() {
mDetailsFunctionsController.mPreviousFunction = UsbManager.FUNCTION_PTP;

View File

@@ -21,11 +21,14 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.KeyguardManager;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.os.SystemProperties;
import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
@@ -33,6 +36,7 @@ import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import androidx.preference.SwitchPreference;
import com.android.settings.flags.Flags;
import com.android.settings.testutils.shadow.ShadowUtils;
import org.junit.Before;
@@ -43,6 +47,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@@ -57,18 +62,18 @@ public class UsbDetailsTranscodeMtpControllerTest {
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
private UsbDetailsTranscodeMtpController mUnderTest;
private UsbDetailsFragment mFragment;
@Mock
private UsbBackend mUsbBackend;
@Mock
private UsbDetailsFragment mFragment;
@Mock
private FragmentActivity mActivity;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mFragment = spy(new UsbDetailsFragment());
mContext = RuntimeEnvironment.application;
mPreferenceManager = new PreferenceManager(mContext);
mScreen = mPreferenceManager.createPreferenceScreen(mContext);
@@ -84,11 +89,12 @@ public class UsbDetailsTranscodeMtpControllerTest {
mPreference = new PreferenceCategory(mContext);
mPreference.setKey(mUnderTest.getPreferenceKey());
mScreen.addPreference(mPreference);
mUnderTest.displayPreference(mScreen);
}
@Test
public void displayRefresh_noUsbConnection_shouldDisablePrefCategory() {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(false /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE,
@@ -99,7 +105,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Test
public void displayRefresh_noDataTransfer_shouldDisablePrefCategory() {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_NONE, POWER_ROLE_NONE,
@@ -110,7 +115,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Test
public void displayRefresh_noDataRole_shouldDisablePrefCategory() throws InterruptedException {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE,
@@ -122,7 +126,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void displayRefresh_fileTransfer_withAbsentProp_shouldCheck() {
mUnderTest.displayPreference(mScreen);
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE,
@@ -134,7 +137,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void displayRefresh_fileTransfer_withUnsetProp_shouldUncheck() {
mUnderTest.displayPreference(mScreen);
SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, Boolean.toString(false));
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
@@ -147,7 +149,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void displayRefresh_fileTransfer_withSetProp_shouldCheck() {
mUnderTest.displayPreference(mScreen);
SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, Boolean.toString(true));
when(mUsbBackend.areAllRolesSupported()).thenReturn(true);
@@ -160,7 +161,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void click_checked_shouldSetSystemProperty() {
mUnderTest.displayPreference(mScreen);
getSwitchPreference().performClick();
assertThat(SystemProperties.getBoolean(TRANSCODE_MTP_SYS_PROP_KEY, false)).isTrue();
}
@@ -168,7 +168,6 @@ public class UsbDetailsTranscodeMtpControllerTest {
@Ignore("b/313362757")
@Test
public void click_unChecked_shouldUnsetSystemProperty() {
mUnderTest.displayPreference(mScreen);
getSwitchPreference().performClick();
getSwitchPreference().performClick();
assertThat(SystemProperties.getBoolean(TRANSCODE_MTP_SYS_PROP_KEY, true)).isFalse();
@@ -181,6 +180,21 @@ public class UsbDetailsTranscodeMtpControllerTest {
assertThat(mUnderTest.isAvailable()).isFalse();
}
@Test
@RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES)
public void onClick_userAuthenticated() {
setAuthPassesAutomatically();
mUnderTest.onPreferenceClick(null);
assertThat(mFragment.isUserAuthenticated()).isTrue();
}
private void setAuthPassesAutomatically() {
Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class))
.setIsKeyguardSecure(false);
}
private SwitchPreference getSwitchPreference() {
return (SwitchPreference) mPreference.getPreference(0);
}

View File

@@ -104,7 +104,7 @@ public class BatteryDefenderTipTest {
@Test
public void updatePreference_shouldSetPrimaryButtonText() {
String expectedText = mContext.getString(R.string.battery_tip_charge_to_full_button);
String expectedText = mContext.getString(R.string.learn_more);
mBatteryDefenderTip.updatePreference(mCardPreference);
@@ -113,7 +113,7 @@ public class BatteryDefenderTipTest {
@Test
public void updatePreference_shouldSetSecondaryButtonText() {
String expected = mContext.getString(R.string.learn_more);
String expected = mContext.getString(R.string.battery_tip_charge_to_full_button);
mBatteryDefenderTip.updatePreference(mCardPreference);
@@ -121,10 +121,10 @@ public class BatteryDefenderTipTest {
}
@Test
public void updatePreference_shouldSetSecondaryButtonVisible() {
public void updatePreference_shouldSetPrimaryButtonVisible() {
mBatteryDefenderTip.updatePreference(mCardPreference);
verify(mCardPreference).setSecondaryButtonVisible(true);
verify(mCardPreference).setPrimaryButtonVisible(true);
}
@Test
@@ -138,19 +138,19 @@ public class BatteryDefenderTipTest {
}
@Test
public void updatePreference_whenNotCharging_setPrimaryButtonVisibleToBeFalse() {
public void updatePreference_whenNotCharging_setSecondaryButtonVisibleToBeFalse() {
mBatteryDefenderTip.updatePreference(mCardPreference);
verify(mCardPreference).setPrimaryButtonVisible(false);
verify(mCardPreference).setSecondaryButtonVisible(false);
}
@Test
public void updatePreference_whenGetChargingStatusFailed_setPrimaryButtonVisibleToBeFalse() {
public void updatePreference_whenGetChargingStatusFailed_setSecondaryButtonVisibleToBeFalse() {
fakeGetChargingStatusFailed();
mBatteryDefenderTip.updatePreference(mCardPreference);
verify(mCardPreference).setPrimaryButtonVisible(false);
verify(mCardPreference).setSecondaryButtonVisible(false);
}
private void fakeGetChargingStatusFailed() {

View File

@@ -369,7 +369,7 @@ public class AppLocalePickerActivityTest {
// In the proto file, en-US's uid list contains 103, the notificationCount equals 1, and
// LastNotificationTime > 0.
NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
assertThat(info.getUidCollection().contains(sUid)).isTrue();
assertThat(info.getUidCollection()).contains(sUid);
assertThat(info.getNotificationCount()).isEqualTo(1);
assertThat(info.getDismissCount()).isEqualTo(0);
assertThat(info.getLastNotificationTimeMs()).isNotEqualTo(0);
@@ -440,7 +440,7 @@ public class AppLocalePickerActivityTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_LOCALE_NOTIFICATION_ENABLED)
public void testEvaluateLocaleNotification_localeUpdateReachThreshold_uidAddedNoNotification()
public void testEvaluateLocaleNotification_localeUpdateReachThreshold_noUidNorNotification()
throws Exception {
// App with uid 106 changed its locale from System to en-US.
sUid = 106;
@@ -460,7 +460,7 @@ public class AppLocalePickerActivityTest {
// In the proto file, en-US's uid list contains 106, the notificationCount equals 2, and
// LastNotificationTime > 0.
NotificationInfo info = mDataManager.getNotificationInfo(EN_US);
assertThat(info.getUidCollection()).contains(sUid);
assertThat(info.getUidCollection().contains(sUid)).isFalse();
assertThat(info.getNotificationCount()).isEqualTo(2);
assertThat(info.getDismissCount()).isEqualTo(0);
assertThat(info.getLastNotificationTimeMs()).isEqualTo(lastNotificationTime);

View File

@@ -68,6 +68,18 @@ public class LocaleNotificationDataManagerTest {
info.getLastNotificationTimeMs());
}
@Test
public void testRemoveNotificationInfo() {
String locale = "en-US";
Set<Integer> uidSet = Set.of(101);
NotificationInfo info = new NotificationInfo(uidSet, 1, 1, 100L, 1000);
mDataManager.putNotificationInfo(locale, info);
assertThat(mDataManager.getNotificationInfo(locale)).isEqualTo(info);
mDataManager.removeNotificationInfo(locale);
assertThat(mDataManager.getNotificationInfo(locale)).isNull();
}
@Test
public void testGetNotificationMap() {
String enUS = "en-US";

View File

@@ -71,6 +71,19 @@ public class NotificationControllerTest {
assertThat(result.getNotificationId()).isEqualTo(id);
}
@Test
public void testRemoveNotificationInfo_removed() throws Exception {
String enUS = "en-US";
Set<Integer> uidSet = Set.of(100, 101);
long lastNotificationTime = Calendar.getInstance().getTimeInMillis();
int id = (int) SystemClock.uptimeMillis();
initSharedPreference(enUS, uidSet, 0, 1, lastNotificationTime, id);
mNotificationController.removeNotificationInfo(enUS);
assertThat(mDataManager.getNotificationInfo(enUS)).isNull();
}
@Test
public void testShouldTriggerNotification_inSystemLocale_returnFalse() throws Exception {
int uid = 102;

View File

@@ -0,0 +1,173 @@
/*
* 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.network.telephony
import android.telephony.CellIdentityCdma
import android.telephony.CellIdentityGsm
import android.telephony.CellInfoCdma
import android.telephony.CellInfoGsm
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.internal.telephony.OperatorInfo
import com.android.settings.network.telephony.CellInfoUtil.getNetworkTitle
import com.android.settings.network.telephony.CellInfoUtil.getOperatorNumeric
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class CellInfoUtilTest {
@Test
fun getNetworkTitle_alphaLong() {
val networkTitle = CELL_IDENTITY_GSM.getNetworkTitle()
assertThat(networkTitle).isEqualTo(LONG)
}
@Test
fun getNetworkTitle_alphaShort() {
val cellIdentity = CellIdentityGsm(
/* lac = */ 1,
/* cid = */ 2,
/* arfcn = */ 3,
/* bsic = */ 4,
/* mccStr = */ "123",
/* mncStr = */ "01",
/* alphal = */ "",
/* alphas = */ SHORT,
/* additionalPlmns = */ emptyList(),
)
val networkTitle = cellIdentity.getNetworkTitle()
assertThat(networkTitle).isEqualTo(SHORT)
}
@Test
fun getNetworkTitle_operatorNumeric() {
val cellIdentity = CellIdentityGsm(
/* lac = */ 1,
/* cid = */ 2,
/* arfcn = */ 3,
/* bsic = */ 4,
/* mccStr = */ "123",
/* mncStr = */ "01",
/* alphal = */ "",
/* alphas = */ "",
/* additionalPlmns = */ emptyList(),
)
val networkTitle = cellIdentity.getNetworkTitle()
assertThat(networkTitle).isEqualTo("12301")
}
@Test
fun getNetworkTitle_null() {
val cellIdentity = CellIdentityGsm(
/* lac = */ 1,
/* cid = */ 2,
/* arfcn = */ 3,
/* bsic = */ 4,
/* mccStr = */ null,
/* mncStr = */ null,
/* alphal = */ null,
/* alphas = */ null,
/* additionalPlmns = */ emptyList(),
)
val networkTitle = cellIdentity.getNetworkTitle()
assertThat(networkTitle).isNull()
}
@Test
fun convertOperatorInfoToCellInfo() {
val operatorInfo = OperatorInfo(LONG, SHORT, "12301")
val cellInfo = CellInfoUtil.convertOperatorInfoToCellInfo(operatorInfo)
assertThat(cellInfo.cellIdentity.mccString).isEqualTo("123")
assertThat(cellInfo.cellIdentity.mncString).isEqualTo("01")
assertThat(cellInfo.cellIdentity.operatorAlphaLong).isEqualTo(LONG)
assertThat(cellInfo.cellIdentity.operatorAlphaShort).isEqualTo(SHORT)
}
@Test
fun cellInfoListToString() {
val cellInfoList =
listOf(
CellInfoCdma().apply {
cellIdentity = CELL_IDENTITY_CDMA
},
CellInfoGsm().apply {
isRegistered = true
cellIdentity = CELL_IDENTITY_GSM
},
)
val string = CellInfoUtil.cellInfoListToString(cellInfoList)
assertThat(string).isEqualTo(
"{CellType = CellInfoCdma, isRegistered = false, " +
"mcc = null, mnc = null, alphaL = Long, alphaS = Short}, " +
"{CellType = CellInfoGsm, isRegistered = true, " +
"mcc = 123, mnc = 01, alphaL = Long, alphaS = Short}"
)
}
@Test
fun getOperatorNumeric_cdma() {
val operatorNumeric = CELL_IDENTITY_CDMA.getOperatorNumeric()
assertThat(operatorNumeric).isNull()
}
@Test
fun getOperatorNumeric_gsm() {
val operatorNumeric = CELL_IDENTITY_GSM.getOperatorNumeric()
assertThat(operatorNumeric).isEqualTo("12301")
}
private companion object {
const val LONG = "Long"
const val SHORT = "Short"
val CELL_IDENTITY_GSM = CellIdentityGsm(
/* lac = */ 1,
/* cid = */ 2,
/* arfcn = */ 3,
/* bsic = */ 4,
/* mccStr = */ "123",
/* mncStr = */ "01",
/* alphal = */ LONG,
/* alphas = */ SHORT,
/* additionalPlmns = */ emptyList(),
)
val CELL_IDENTITY_CDMA = CellIdentityCdma(
/* nid = */ 1,
/* sid = */ 2,
/* bid = */ 3,
/* lon = */ 4,
/* lat = */ 5,
/* alphal = */ LONG,
/* alphas = */ SHORT,
)
}
}