Snap for 11722130 from ea8c0f7716 to 24Q3-release

Change-Id: If21ee31077b197be0812efc34135f793b47eb6b5
This commit is contained in:
Android Build Coastguard Worker
2024-04-16 23:21:44 +00:00
39 changed files with 512 additions and 743 deletions

View File

@@ -8794,13 +8794,13 @@
<!-- [CHAR LIMIT=NONE] App notification settings: link to app notification settings--> <!-- [CHAR LIMIT=NONE] App notification settings: link to app notification settings-->
<string name="app_settings_link">Additional settings in the app</string> <string name="app_settings_link">Additional settings in the app</string>
<!-- [CHAR LIMIT=20] 3-dot menu option, reloads the screen to show channels that have not <!-- [CHAR LIMIT=35] 3-dot menu option, reloads the screen to show channels that have not
received notifications in the last two week --> received notifications in the last two week -->
<string name="show_unused_channels">Show unused channels</string> <string name="show_unused_channels">Show unused categories</string>
<!-- [CHAR LIMIT=20] 3-dot menu option, reloads the screen to hide channels that have not <!-- [CHAR LIMIT=35] 3-dot menu option, reloads the screen to hide channels that have not
received notifications in the last two week --> received notifications in the last two week -->
<string name="hide_unused_channels">Hide unused channels</string> <string name="hide_unused_channels">Hide unused categories</string>
<!-- [CHAR LIMIT=NONE] Footer listing a count of deleted channels. --> <!-- [CHAR LIMIT=NONE] Footer listing a count of deleted channels. -->
<string name="deleted_channels">{count, plural, <string name="deleted_channels">{count, plural,

View File

@@ -20,14 +20,6 @@
android:key="system_dashboard_screen" android:key="system_dashboard_screen"
android:title="@string/header_category_system"> android:title="@string/header_category_system">
<Preference
android:key="language_input_settings"
android:title="@string/language_settings"
android:icon="@drawable/ic_settings_language"
android:order="-260"
android:fragment="com.android.settings.language.LanguageAndInputSettings"
settings:controller="com.android.settings.language.LanguageAndInputPreferenceController"/>
<Preference <Preference
android:key="language_settings" android:key="language_settings"
android:title="@string/languages_settings" android:title="@string/languages_settings"

View File

@@ -50,6 +50,7 @@ import com.android.settings.homepage.DeepLinkHomepageActivityInternal;
import com.android.settings.homepage.SettingsHomepageActivity; import com.android.settings.homepage.SettingsHomepageActivity;
import com.android.settings.overlay.FeatureFactory; import com.android.settings.overlay.FeatureFactory;
import com.android.settings.password.ChooseLockPattern; import com.android.settings.password.ChooseLockPattern;
import com.android.settings.privatespace.PrivateSpaceSetupActivity;
import com.android.settings.remoteauth.RemoteAuthActivity; import com.android.settings.remoteauth.RemoteAuthActivity;
import com.android.settings.remoteauth.RemoteAuthActivityInternal; import com.android.settings.remoteauth.RemoteAuthActivityInternal;
@@ -264,6 +265,7 @@ public class ActivityEmbeddingRulesController {
addActivityFilter(activityFilters, RemoteAuthActivity.class); addActivityFilter(activityFilters, RemoteAuthActivity.class);
addActivityFilter(activityFilters, RemoteAuthActivityInternal.class); addActivityFilter(activityFilters, RemoteAuthActivityInternal.class);
addActivityFilter(activityFilters, ChooseLockPattern.class); addActivityFilter(activityFilters, ChooseLockPattern.class);
addActivityFilter(activityFilters, PrivateSpaceSetupActivity.class);
String action = mContext.getString(R.string.config_avatar_picker_action); String action = mContext.getString(R.string.config_avatar_picker_action);
addActivityFilter(activityFilters, new Intent(action)); addActivityFilter(activityFilters, new Intent(action));

View File

@@ -135,7 +135,6 @@ import com.android.settings.inputmethod.SpellCheckersSettings;
import com.android.settings.inputmethod.TrackpadSettings; import com.android.settings.inputmethod.TrackpadSettings;
import com.android.settings.inputmethod.UserDictionaryList; import com.android.settings.inputmethod.UserDictionaryList;
import com.android.settings.inputmethod.UserDictionarySettings; import com.android.settings.inputmethod.UserDictionarySettings;
import com.android.settings.language.LanguageAndInputSettings;
import com.android.settings.language.LanguageSettings; import com.android.settings.language.LanguageSettings;
import com.android.settings.localepicker.LocaleListEditor; import com.android.settings.localepicker.LocaleListEditor;
import com.android.settings.location.LocationServices; import com.android.settings.location.LocationServices;
@@ -226,7 +225,6 @@ public class SettingsGateway {
DateTimeSettings.class.getName(), DateTimeSettings.class.getName(),
LocaleListEditor.class.getName(), LocaleListEditor.class.getName(),
AvailableVirtualKeyboardFragment.class.getName(), AvailableVirtualKeyboardFragment.class.getName(),
LanguageAndInputSettings.class.getName(),
LanguageSettings.class.getName(), LanguageSettings.class.getName(),
KeyboardSettings.class.getName(), KeyboardSettings.class.getName(),
ModifierKeysSettings.class.getName(), ModifierKeysSettings.class.getName(),

View File

@@ -38,7 +38,6 @@ import com.android.settings.fuelgauge.batterysaver.BatterySaverSettings;
import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary; import com.android.settings.fuelgauge.batteryusage.PowerUsageSummary;
import com.android.settings.gestures.GestureSettings; import com.android.settings.gestures.GestureSettings;
import com.android.settings.homepage.TopLevelSettings; import com.android.settings.homepage.TopLevelSettings;
import com.android.settings.language.LanguageAndInputSettings;
import com.android.settings.network.NetworkDashboardFragment; import com.android.settings.network.NetworkDashboardFragment;
import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.ConfigureNotificationSettings;
import com.android.settings.notification.SoundSettings; import com.android.settings.notification.SoundSettings;
@@ -102,8 +101,6 @@ public class DashboardFragmentRegistry {
CategoryKey.CATEGORY_ACCOUNT); CategoryKey.CATEGORY_ACCOUNT);
PARENT_TO_CATEGORY_KEY_MAP.put( PARENT_TO_CATEGORY_KEY_MAP.put(
SystemDashboardFragment.class.getName(), CategoryKey.CATEGORY_SYSTEM); SystemDashboardFragment.class.getName(), CategoryKey.CATEGORY_SYSTEM);
PARENT_TO_CATEGORY_KEY_MAP.put(LanguageAndInputSettings.class.getName(),
CategoryKey.CATEGORY_SYSTEM_LANGUAGE);
// TODO(b/242680328) Tie new category key to LanguageSettings and KeyboardSettings page // TODO(b/242680328) Tie new category key to LanguageSettings and KeyboardSettings page
PARENT_TO_CATEGORY_KEY_MAP.put(DevelopmentSettingsDashboardFragment.class.getName(), PARENT_TO_CATEGORY_KEY_MAP.put(DevelopmentSettingsDashboardFragment.class.getName(),
CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT); CategoryKey.CATEGORY_SYSTEM_DEVELOPMENT);

View File

@@ -78,6 +78,10 @@ public class BluetoothCodecListPreferenceController
@Override @Override
public boolean onPreferenceChange(@Nullable Preference preference, @NonNull Object newValue) { public boolean onPreferenceChange(@Nullable Preference preference, @NonNull Object newValue) {
if (!Flags.a2dpOffloadCodecExtensibilitySettings()) {
return false;
}
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "onPreferenceChange: newValue=" + (String) newValue); Log.d(TAG, "onPreferenceChange: newValue=" + (String) newValue);
} }
@@ -120,6 +124,10 @@ public class BluetoothCodecListPreferenceController
@Override @Override
public void updateState(@Nullable Preference preference) { public void updateState(@Nullable Preference preference) {
super.updateState(preference); super.updateState(preference);
if (!Flags.a2dpOffloadCodecExtensibilitySettings()) {
return;
}
final List<String> codecIds = new ArrayList<>(); final List<String> codecIds = new ArrayList<>();
final List<String> labels = new ArrayList<>(); final List<String> labels = new ArrayList<>();
String selectedCodecId = mDefaultValue; String selectedCodecId = mDefaultValue;

View File

@@ -80,7 +80,6 @@ public class MainlineModuleVersionPreferenceController extends BasePreferenceCon
try { try {
mModuleVersion = mModuleVersion =
mPackageManager.getPackageInfo(moduleProvider, 0 /* flags */).versionName; mPackageManager.getPackageInfo(moduleProvider, 0 /* flags */).versionName;
return;
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Failed to get mainline version.", e); Log.e(TAG, "Failed to get mainline version.", e);
mModuleVersion = null; mModuleVersion = null;
@@ -124,7 +123,8 @@ public class MainlineModuleVersionPreferenceController extends BasePreferenceCon
return mModuleVersion; return mModuleVersion;
} }
return DateFormat.getLongDateFormat(mContext).format(parsedDate.get()); String format = DateFormat.getBestDateTimePattern(Locale.getDefault(), "dMMMMyyyy");
return DateFormat.format(format, parsedDate.get());
} }
private Optional<Date> parseDateFromVersionName(String text) { private Optional<Date> parseDateFromVersionName(String text) {

View File

@@ -18,7 +18,6 @@ package com.android.settings.inputmethod;
import android.content.Context; import android.content.Context;
import android.hardware.input.InputManager; import android.hardware.input.InputManager;
import android.util.FeatureFlagUtils;
import androidx.preference.Preference; import androidx.preference.Preference;
@@ -78,9 +77,7 @@ public class KeyboardPreferenceController extends BasePreferenceController
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
return FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI) return AVAILABLE;
? AVAILABLE
: CONDITIONALLY_UNAVAILABLE;
} }
private void updateSummary() { private void updateSummary() {

View File

@@ -23,7 +23,6 @@ import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROF
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.util.FeatureFlagUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@@ -111,11 +110,5 @@ public class KeyboardSettings extends DashboardFragment {
} }
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.keyboard_settings) { new BaseSearchIndexProvider(R.xml.keyboard_settings);
@Override
protected boolean isPageSearchEnabled(Context context) {
return FeatureFlagUtils
.isEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
}
};
} }

View File

@@ -20,7 +20,6 @@ import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.provider.Settings; import android.provider.Settings;
import android.util.FeatureFlagUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
@@ -69,8 +68,7 @@ public class KeyboardSettingsPreferenceController extends BasePreferenceControll
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboardList(); List<HardKeyboardDeviceInfo> newHardKeyboards = getHardKeyboardList();
if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI) if (!newHardKeyboards.isEmpty()) {
&& !newHardKeyboards.isEmpty()) {
for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) { for (HardKeyboardDeviceInfo hardKeyboardDeviceInfo : newHardKeyboards) {
if (mCachedDevice.getAddress() != null if (mCachedDevice.getAddress() != null
&& hardKeyboardDeviceInfo.mBluetoothAddress != null && hardKeyboardDeviceInfo.mBluetoothAddress != null

View File

@@ -110,7 +110,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
private Intent mIntentWaitingForResult; private Intent mIntentWaitingForResult;
private boolean mIsNewKeyboardSettings;
private boolean mSupportsFirmwareUpdate; private boolean mSupportsFirmwareUpdate;
static final String EXTRA_BT_ADDRESS = "extra_bt_address"; static final String EXTRA_BT_ADDRESS = "extra_bt_address";
@@ -152,8 +151,6 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
if (mSupportsFirmwareUpdate) { if (mSupportsFirmwareUpdate) {
mFeatureProvider.addFirmwareUpdateCategory(getContext(), getPreferenceScreen()); mFeatureProvider.addFirmwareUpdateCategory(getContext(), getPreferenceScreen());
} }
mIsNewKeyboardSettings = FeatureFlagUtils.isEnabled(
getContext(), FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
boolean isModifierKeySettingsEnabled = FeatureFlagUtils boolean isModifierKeySettingsEnabled = FeatureFlagUtils
.isEnabled(getContext(), FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_MODIFIER_KEY); .isEnabled(getContext(), FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_MODIFIER_KEY);
if (!isModifierKeySettingsEnabled) { if (!isModifierKeySettingsEnabled) {
@@ -287,27 +284,19 @@ public final class PhysicalKeyboardFragment extends SettingsPreferenceFragment
// TODO(yukawa): Consider using com.android.settings.widget.GearPreference // TODO(yukawa): Consider using com.android.settings.widget.GearPreference
final Preference pref = new Preference(getPrefContext()); final Preference pref = new Preference(getPrefContext());
pref.setTitle(hardKeyboardDeviceInfo.mDeviceName); pref.setTitle(hardKeyboardDeviceInfo.mDeviceName);
if (mIsNewKeyboardSettings) { String currentLayout =
String currentLayout = NewKeyboardSettingsUtils.getSelectedKeyboardLayoutLabelForUser(getContext(),
NewKeyboardSettingsUtils.getSelectedKeyboardLayoutLabelForUser(getContext(), UserHandle.myUserId(), hardKeyboardDeviceInfo.mDeviceIdentifier);
UserHandle.myUserId(), hardKeyboardDeviceInfo.mDeviceIdentifier); if (currentLayout != null) {
if (currentLayout != null) { pref.setSummary(currentLayout);
pref.setSummary(currentLayout);
}
pref.setOnPreferenceClickListener(
preference -> {
showEnabledLocalesKeyboardLayoutList(
hardKeyboardDeviceInfo.mDeviceIdentifier);
return true;
});
} else {
pref.setSummary(hardKeyboardDeviceInfo.mLayoutLabel);
pref.setOnPreferenceClickListener(
preference -> {
showKeyboardLayoutDialog(hardKeyboardDeviceInfo.mDeviceIdentifier);
return true;
});
} }
pref.setOnPreferenceClickListener(
preference -> {
showEnabledLocalesKeyboardLayoutList(
hardKeyboardDeviceInfo.mDeviceIdentifier);
return true;
});
category.addPreference(pref); category.addPreference(pref);
StringBuilder vendorAndProductId = new StringBuilder(); StringBuilder vendorAndProductId = new StringBuilder();
String vendorId = String.valueOf(hardKeyboardDeviceInfo.mVendorId); String vendorId = String.valueOf(hardKeyboardDeviceInfo.mVendorId);

View File

@@ -1,66 +0,0 @@
/*
* Copyright (C) 2019 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.language;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.FeatureFlagUtils;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import com.android.settings.core.BasePreferenceController;
import java.util.List;
public class LanguageAndInputPreferenceController extends BasePreferenceController {
private PackageManager mPackageManager;
private InputMethodManager mInputMethodManager;
public LanguageAndInputPreferenceController(Context context, String key) {
super(context, key);
mPackageManager = mContext.getPackageManager();
mInputMethodManager = mContext.getSystemService(InputMethodManager.class);
}
@Override
public int getAvailabilityStatus() {
boolean isFeatureOn = FeatureFlagUtils
.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
return isFeatureOn ? CONDITIONALLY_UNAVAILABLE : AVAILABLE;
}
@Override
public CharSequence getSummary() {
final String flattenComponent = Settings.Secure.getString(
mContext.getContentResolver(), Settings.Secure.DEFAULT_INPUT_METHOD);
if (!TextUtils.isEmpty(flattenComponent)) {
final String pkg = ComponentName.unflattenFromString(flattenComponent)
.getPackageName();
final List<InputMethodInfo> imis = mInputMethodManager.getInputMethodList();
for (InputMethodInfo imi : imis) {
if (TextUtils.equals(imi.getPackageName(), pkg)) {
return imi.loadLabel(mPackageManager);
}
}
}
return "";
}
}

View File

@@ -1,168 +0,0 @@
/*
* Copyright (C) 2016 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.language;
import static android.app.admin.DevicePolicyResources.Strings.Settings.PERSONAL_DICTIONARY_FOR_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Settings.SPELL_CHECKER_FOR_WORK;
import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_KEYBOARDS_AND_TOOLS;
import android.app.Activity;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.os.Bundle;
import android.util.FeatureFlagUtils;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.inputmethod.PhysicalKeyboardPreferenceController;
import com.android.settings.inputmethod.SpellCheckerPreferenceController;
import com.android.settings.inputmethod.VirtualKeyboardPreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.widget.PreferenceCategoryController;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@SearchIndexable
public class LanguageAndInputSettings extends DashboardFragment {
private static final String TAG = "LangAndInputSettings";
private static final String KEY_KEYBOARDS_CATEGORY = "keyboards_category";
private static final String KEY_SPEECH_CATEGORY = "speech_category";
private static final String KEY_ON_DEVICE_RECOGNITION = "odsr_settings";
private static final String KEY_TEXT_TO_SPEECH = "tts_settings_summary";
private static final String KEY_POINTER_CATEGORY = "pointer_category";
@Override
public int getMetricsCategory() {
return SettingsEnums.SETTINGS_LANGUAGE_CATEGORY;
}
@Override
protected String getLogTag() {
return TAG;
}
@Override
public void onResume() {
super.onResume();
// Hack to update action bar title. It's necessary to refresh title because this page user
// can change locale from here and fragment won't relaunch. Once language changes, title
// must display in the new language.
final Activity activity = getActivity();
if (activity == null) {
return;
}
activity.setTitle(R.string.language_settings);
}
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
replaceEnterpriseStringTitle("language_and_input_for_work_category",
WORK_PROFILE_KEYBOARDS_AND_TOOLS,
R.string.language_and_input_for_work_category_title);
replaceEnterpriseStringTitle("spellcheckers_settings_for_work_pref",
SPELL_CHECKER_FOR_WORK,
R.string.spellcheckers_settings_for_work_title);
replaceEnterpriseStringTitle("user_dictionary_settings_for_work_pref",
PERSONAL_DICTIONARY_FOR_WORK,
R.string.user_dict_settings_for_work_title);
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.language_and_input;
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getSettingsLifecycle());
}
private static List<AbstractPreferenceController> buildPreferenceControllers(
@NonNull Context context, @Nullable Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
// Input
final VirtualKeyboardPreferenceController virtualKeyboardPreferenceController =
new VirtualKeyboardPreferenceController(context);
final PhysicalKeyboardPreferenceController physicalKeyboardPreferenceController =
new PhysicalKeyboardPreferenceController(context, lifecycle);
controllers.add(virtualKeyboardPreferenceController);
controllers.add(physicalKeyboardPreferenceController);
controllers.add(new PreferenceCategoryController(context,
KEY_KEYBOARDS_CATEGORY).setChildren(
Arrays.asList(virtualKeyboardPreferenceController,
physicalKeyboardPreferenceController)));
// Speech
final DefaultVoiceInputPreferenceController defaultVoiceInputPreferenceController =
new DefaultVoiceInputPreferenceController(context, lifecycle);
final TtsPreferenceController ttsPreferenceController =
new TtsPreferenceController(context, KEY_TEXT_TO_SPEECH);
final OnDeviceRecognitionPreferenceController onDeviceRecognitionPreferenceController =
new OnDeviceRecognitionPreferenceController(context, KEY_ON_DEVICE_RECOGNITION);
controllers.add(defaultVoiceInputPreferenceController);
controllers.add(ttsPreferenceController);
List<AbstractPreferenceController> speechCategoryChildren = new ArrayList<>(
List.of(defaultVoiceInputPreferenceController, ttsPreferenceController));
if (onDeviceRecognitionPreferenceController.isAvailable()) {
controllers.add(onDeviceRecognitionPreferenceController);
speechCategoryChildren.add(onDeviceRecognitionPreferenceController);
}
controllers.add(new PreferenceCategoryController(context, KEY_SPEECH_CATEGORY)
.setChildren(speechCategoryChildren));
// Pointer
final PointerSpeedController pointerController = new PointerSpeedController(context);
controllers.add(pointerController);
controllers.add(new PreferenceCategoryController(context,
KEY_POINTER_CATEGORY).setChildren(Arrays.asList(pointerController)));
// Input Assistance
controllers.add(new SpellCheckerPreferenceController(context));
return controllers;
}
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.language_and_input) {
@Override
public List<AbstractPreferenceController> createPreferenceControllers(
Context context) {
return buildPreferenceControllers(context, null);
}
@Override
protected boolean isPageSearchEnabled(Context context) {
return !FeatureFlagUtils
.isEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
}
};
}

View File

@@ -19,7 +19,6 @@ package com.android.settings.language;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.util.FeatureFlagUtils;
import com.android.settings.Settings; import com.android.settings.Settings;
import com.android.settings.core.BasePreferenceController; import com.android.settings.core.BasePreferenceController;
@@ -29,28 +28,14 @@ import com.android.settings.core.BasePreferenceController;
* TODO(b/273642892): When new layout is on board, this class shall be removed. * TODO(b/273642892): When new layout is on board, this class shall be removed.
*/ */
public class LanguagePreferenceController extends BasePreferenceController { public class LanguagePreferenceController extends BasePreferenceController {
private static final String TAG = LanguagePreferenceController.class.getSimpleName();
private boolean mCacheIsFeatureOn = false;
public LanguagePreferenceController(Context context, String key) { public LanguagePreferenceController(Context context, String key) {
super(context, key); super(context, key);
} }
@Override @Override
public int getAvailabilityStatus() { public int getAvailabilityStatus() {
boolean isFeatureOn = FeatureFlagUtils setActivityEnabled(mContext, Settings.LanguageSettingsActivity.class, true);
.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI); return AVAILABLE;
// LanguageSettingsActivity is a new entry page for new language layout.
// LanguageAndInputSettingsActivity is existed entry page for current language layout.
if (mCacheIsFeatureOn != isFeatureOn) {
setActivityEnabled(
mContext, Settings.LanguageAndInputSettingsActivity.class, !isFeatureOn);
setActivityEnabled(mContext, Settings.LanguageSettingsActivity.class, isFeatureOn);
mCacheIsFeatureOn = isFeatureOn;
}
return isFeatureOn ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
} }
private static void setActivityEnabled(Context context, Class klass, final boolean isEnabled) { private static void setActivityEnabled(Context context, Class klass, final boolean isEnabled) {

View File

@@ -19,7 +19,6 @@ package com.android.settings.language;
import android.app.Activity; import android.app.Activity;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.util.FeatureFlagUtils;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@@ -112,8 +111,7 @@ public class LanguageSettings extends DashboardFragment {
} }
@Override @Override
protected boolean isPageSearchEnabled(Context context) { protected boolean isPageSearchEnabled(Context context) {
return FeatureFlagUtils return true;
.isEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
} }
}; };
} }

View File

@@ -81,7 +81,7 @@ public class MediaDeviceUpdateWorker extends SliceBackgroundWorker
mIsTouched = false; mIsTouched = false;
if (mLocalMediaManager == null || !TextUtils.equals(mPackageName, if (mLocalMediaManager == null || !TextUtils.equals(mPackageName,
mLocalMediaManager.getPackageName())) { mLocalMediaManager.getPackageName())) {
mLocalMediaManager = new LocalMediaManager(mContext, mPackageName, null); mLocalMediaManager = new LocalMediaManager(mContext, mPackageName);
} }
// Delaying initialization to allow mocking in Roboelectric tests. // Delaying initialization to allow mocking in Roboelectric tests.

View File

@@ -92,8 +92,7 @@ public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements
} }
if (mLocalMediaManager == null || !TextUtils.equals(mPackageName, if (mLocalMediaManager == null || !TextUtils.equals(mPackageName,
mLocalMediaManager.getPackageName())) { mLocalMediaManager.getPackageName())) {
mLocalMediaManager = new LocalMediaManager(mContext, mPackageName, mLocalMediaManager = new LocalMediaManager(mContext, mPackageName);
null /* notification */);
} }
mLocalMediaManager.registerCallback(this); mLocalMediaManager.registerCallback(this);
mLocalMediaManager.startScan(); mLocalMediaManager.startScan();

View File

@@ -1,69 +0,0 @@
/*
* 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
import android.content.Context
import android.os.OutcomeReceiver
import android.telephony.satellite.SatelliteManager
import android.util.Log
import androidx.concurrent.futures.CallbackToFutureAdapter
import com.google.common.util.concurrent.Futures.immediateFuture
import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.Executor
/**
* Utility class for interacting with the SatelliteManager API.
*/
object SatelliteManagerUtil {
private const val TAG: String = "SatelliteManagerUtil"
/**
* Checks if the satellite modem is enabled.
*
* @param context The application context
* @param executor The executor to run the asynchronous operation on
* @return A ListenableFuture that will resolve to `true` if the satellite modem enabled,
* `false` otherwise.
*/
@JvmStatic
fun requestIsEnabled(context: Context, executor: Executor): ListenableFuture<Boolean> {
val satelliteManager: SatelliteManager? =
context.getSystemService(SatelliteManager::class.java)
if (satelliteManager == null) {
Log.w(TAG, "SatelliteManager is null")
return immediateFuture(false)
}
return CallbackToFutureAdapter.getFuture { completer ->
satelliteManager.requestIsEnabled(executor,
object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
override fun onResult(result: Boolean) {
Log.i(TAG, "Satellite modem enabled status: $result")
completer.set(result)
}
override fun onError(error: SatelliteManager.SatelliteException) {
super.onError(error)
Log.w(TAG, "Can't get satellite modem enabled status", error)
completer.set(false)
}
})
"requestIsEnabled"
}
}
}

View File

@@ -0,0 +1,137 @@
/*
* 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
import android.content.Context
import android.os.OutcomeReceiver
import android.telephony.satellite.SatelliteManager
import android.telephony.satellite.SatelliteModemStateCallback
import android.util.Log
import androidx.annotation.VisibleForTesting
import androidx.concurrent.futures.CallbackToFutureAdapter
import com.google.common.util.concurrent.Futures.immediateFuture
import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.Executor
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.flowOf
/**
* A repository class for interacting with the SatelliteManager API.
*/
class SatelliteRepository(
private val context: Context,
) {
/**
* Checks if the satellite modem is enabled.
*
* @param executor The executor to run the asynchronous operation on
* @return A ListenableFuture that will resolve to `true` if the satellite modem enabled,
* `false` otherwise.
*/
fun requestIsEnabled(executor: Executor): ListenableFuture<Boolean> {
val satelliteManager: SatelliteManager? =
context.getSystemService(SatelliteManager::class.java)
if (satelliteManager == null) {
Log.w(TAG, "SatelliteManager is null")
return immediateFuture(false)
}
return CallbackToFutureAdapter.getFuture { completer ->
satelliteManager.requestIsEnabled(executor,
object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> {
override fun onResult(result: Boolean) {
Log.i(TAG, "Satellite modem enabled status: $result")
completer.set(result)
}
override fun onError(error: SatelliteManager.SatelliteException) {
super.onError(error)
Log.w(TAG, "Can't get satellite modem enabled status", error)
completer.set(false)
}
})
"requestIsEnabled"
}
}
/**
* Provides a Flow that emits the enabled state of the satellite modem. Updates are triggered
* when the modem state changes.
*
* @param defaultDispatcher The CoroutineDispatcher to use (Defaults to `Dispatchers.Default`).
* @return A Flow emitting `true` when the modem is enabled and `false` otherwise.
*/
fun getIsModemEnabledFlow(
defaultDispatcher: CoroutineDispatcher = Dispatchers.Default,
): Flow<Boolean> {
val satelliteManager: SatelliteManager? =
context.getSystemService(SatelliteManager::class.java)
if (satelliteManager == null) {
Log.w(TAG, "SatelliteManager is null")
return flowOf(false)
}
return callbackFlow {
val callback = SatelliteModemStateCallback { state ->
val isEnabled = convertSatelliteModemStateToEnabledState(state)
Log.i(TAG, "Satellite modem state changed: state=$state, isEnabled=$isEnabled")
trySend(isEnabled)
}
val result = satelliteManager.registerForModemStateChanged(
defaultDispatcher.asExecutor(),
callback
)
Log.i(TAG, "Call registerForModemStateChanged: result=$result")
awaitClose { satelliteManager.unregisterForModemStateChanged(callback) }
}
}
/**
* Converts a [SatelliteManager.SatelliteModemState] to a boolean representing whether the modem
* is enabled.
*
* @param state The SatelliteModemState provided by the SatelliteManager.
* @return `true` if the modem is enabled, `false` otherwise.
*/
@VisibleForTesting
fun convertSatelliteModemStateToEnabledState(
@SatelliteManager.SatelliteModemState state: Int,
): Boolean {
// Mapping table based on logic from b/315928920#comment24
return when (state) {
SatelliteManager.SATELLITE_MODEM_STATE_IDLE,
SatelliteManager.SATELLITE_MODEM_STATE_LISTENING,
SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_TRANSFERRING,
SatelliteManager.SATELLITE_MODEM_STATE_DATAGRAM_RETRYING,
SatelliteManager.SATELLITE_MODEM_STATE_NOT_CONNECTED,
SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED -> true
else -> false
}
}
companion object {
private const val TAG: String = "SatelliteRepository"
}
}

View File

@@ -46,15 +46,18 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.lifecycle.LifecycleRegistry
import com.android.settings.R import com.android.settings.R
import com.android.settings.SidecarFragment import com.android.settings.SidecarFragment
import com.android.settings.network.telephony.SubscriptionActionDialogActivity import com.android.settings.network.telephony.SubscriptionActionDialogActivity
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity
import com.android.settings.spa.SpaActivity.Companion.startSpaActivity import com.android.settings.spa.SpaActivity.Companion.startSpaActivity
import com.android.settings.spa.network.SimOnboardingPageProvider.getRoute import com.android.settings.spa.network.SimOnboardingPageProvider.getRoute
import com.android.settings.wifi.WifiPickerTrackerHelper
import com.android.settingslib.spa.SpaBaseDialogActivity import com.android.settingslib.spa.SpaBaseDialogActivity
import com.android.settingslib.spa.framework.theme.SettingsDimension import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
@@ -74,6 +77,8 @@ import kotlinx.coroutines.launch
class SimOnboardingActivity : SpaBaseDialogActivity() { class SimOnboardingActivity : SpaBaseDialogActivity() {
lateinit var scope: CoroutineScope lateinit var scope: CoroutineScope
lateinit var wifiPickerTrackerHelper: WifiPickerTrackerHelper
lateinit var context: Context
lateinit var showStartingDialog: MutableState<Boolean> lateinit var showStartingDialog: MutableState<Boolean>
lateinit var showError: MutableState<ErrorType> lateinit var showError: MutableState<ErrorType>
lateinit var showProgressDialog: MutableState<Boolean> lateinit var showProgressDialog: MutableState<Boolean>
@@ -86,6 +91,7 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (!this.userManager.isAdminUser) { if (!this.userManager.isAdminUser) {
Log.e(TAG, "It is not the admin user. Unable to toggle subscription.") Log.e(TAG, "It is not the admin user. Unable to toggle subscription.")
finish() finish()
@@ -152,7 +158,10 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
CallbackType.CALLBACK_SETUP_PRIMARY_SIM -> { CallbackType.CALLBACK_SETUP_PRIMARY_SIM -> {
scope.launch { scope.launch {
onboardingService.startSetupPrimarySim(this@SimOnboardingActivity) onboardingService.startSetupPrimarySim(
this@SimOnboardingActivity,
wifiPickerTrackerHelper
)
} }
} }
@@ -184,6 +193,12 @@ class SimOnboardingActivity : SpaBaseDialogActivity() {
showDsdsProgressDialog = rememberSaveable { mutableStateOf(false) } showDsdsProgressDialog = rememberSaveable { mutableStateOf(false) }
showRestartDialog = rememberSaveable { mutableStateOf(false) } showRestartDialog = rememberSaveable { mutableStateOf(false) }
scope = rememberCoroutineScope() scope = rememberCoroutineScope()
context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
wifiPickerTrackerHelper = WifiPickerTrackerHelper(
LifecycleRegistry(lifecycleOwner), context,
null /* WifiPickerTrackerCallback */
)
registerSidecarReceiverFlow() registerSidecarReceiverFlow()

View File

@@ -30,6 +30,7 @@ import com.android.settings.spa.network.setAutomaticData
import com.android.settings.spa.network.setDefaultData import com.android.settings.spa.network.setDefaultData
import com.android.settings.spa.network.setDefaultSms import com.android.settings.spa.network.setDefaultSms
import com.android.settings.spa.network.setDefaultVoice import com.android.settings.spa.network.setDefaultVoice
import com.android.settings.wifi.WifiPickerTrackerHelper
import com.android.settingslib.utils.ThreadUtils import com.android.settingslib.utils.ThreadUtils
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
@@ -336,14 +337,17 @@ class SimOnboardingService {
} }
} }
suspend fun startSetupPrimarySim(context: Context) { suspend fun startSetupPrimarySim(
context: Context,
wifiPickerTrackerHelper: WifiPickerTrackerHelper
) {
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
setDefaultVoice(subscriptionManager, targetPrimarySimCalls) setDefaultVoice(subscriptionManager, targetPrimarySimCalls)
setDefaultSms(subscriptionManager, targetPrimarySimTexts) setDefaultSms(subscriptionManager, targetPrimarySimTexts)
setDefaultData( setDefaultData(
context, context,
subscriptionManager, subscriptionManager,
null, wifiPickerTrackerHelper,
targetPrimarySimMobileData targetPrimarySimMobileData
) )
TelephonyRepository(context).setAutomaticData( TelephonyRepository(context).setAutomaticData(

View File

@@ -26,16 +26,19 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.SatelliteRepository
import com.android.settings.network.SubscriptionUtil import com.android.settings.network.SubscriptionUtil
import com.android.settings.spa.preference.ComposePreferenceController import com.android.settings.spa.preference.ComposePreferenceController
import com.android.settingslib.spa.widget.preference.MainSwitchPreference import com.android.settingslib.spa.widget.preference.MainSwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
class MobileNetworkSwitchController @JvmOverloads constructor( class MobileNetworkSwitchController @JvmOverloads constructor(
context: Context, context: Context,
preferenceKey: String, preferenceKey: String,
private val subscriptionRepository: SubscriptionRepository = SubscriptionRepository(context), private val subscriptionRepository: SubscriptionRepository = SubscriptionRepository(context),
private val satelliteRepository: SatelliteRepository = SatelliteRepository(context)
) : ComposePreferenceController(context, preferenceKey) { ) : ComposePreferenceController(context, preferenceKey) {
private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID private var subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID
@@ -54,7 +57,12 @@ class MobileNetworkSwitchController @JvmOverloads constructor(
subscriptionRepository.isSubscriptionEnabledFlow(subId) subscriptionRepository.isSubscriptionEnabledFlow(subId)
}.collectAsStateWithLifecycle(initialValue = null) }.collectAsStateWithLifecycle(initialValue = null)
val changeable by remember { val changeable by remember {
context.callStateFlow(subId).map { it == TelephonyManager.CALL_STATE_IDLE } combine(
context.callStateFlow(subId).map { it == TelephonyManager.CALL_STATE_IDLE },
satelliteRepository.getIsModemEnabledFlow()
) { isCallStateIdle, isSatelliteModemEnabled ->
isCallStateIdle && !isSatelliteModemEnabled
}
}.collectAsStateWithLifecycle(initialValue = true) }.collectAsStateWithLifecycle(initialValue = true)
MainSwitchPreference(model = object : SwitchPreferenceModel { MainSwitchPreference(model = object : SwitchPreferenceModel {
override val title = stringResource(R.string.mobile_network_use_sim_on) override val title = stringResource(R.string.mobile_network_use_sim_on)

View File

@@ -21,6 +21,8 @@ import android.telephony.SubscriptionManager
import android.telephony.TelephonyCallback import android.telephony.TelephonyCallback
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.util.Log import android.util.Log
import com.android.settings.network.mobileDataEnabledFlow
import com.android.settings.wifi.WifiPickerTrackerHelper
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.asExecutor import kotlinx.coroutines.asExecutor
import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.ProducerScope
@@ -62,6 +64,42 @@ class TelephonyRepository(
telephonyManager.setMobileDataPolicyEnabled(policy, enabled) telephonyManager.setMobileDataPolicyEnabled(policy, enabled)
} }
fun isDataEnabled(
subId: Int,
): Flow<Boolean> {
if (!SubscriptionManager.isValidSubscriptionId(subId)) return flowOf(false)
Log.d(TAG, "register mobileDataEnabledFlow: [$subId]")
return context.mobileDataEnabledFlow(subId)
.map {
Log.d(TAG, "mobileDataEnabledFlow: receive mobile data [$subId] start")
val telephonyManager = context.telephonyManager(subId)
telephonyManager.isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
.also { Log.d(TAG, "mobileDataEnabledFlow: [$subId] isDataEnabled(): $it") }
}
}
fun setMobileData(
subId: Int,
enabled: Boolean,
wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null
) {
if (!SubscriptionManager.isValidSubscriptionId(subId)) return
Log.d(TAG, "setMobileData: $enabled")
MobileNetworkUtils.setMobileDataEnabled(
context,
subId,
enabled /* enabled */,
true /* disableOtherSubscriptions */
)
if (wifiPickerTrackerHelper != null
&& !wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)
) {
wifiPickerTrackerHelper.setCarrierNetworkEnabled(enabled)
}
}
private companion object { private companion object {
private const val TAG = "TelephonyRepository" private const val TAG = "TelephonyRepository"
} }

View File

@@ -68,7 +68,7 @@ public class RemoteVolumeGroupController extends BasePreferenceController implem
public RemoteVolumeGroupController(Context context, String preferenceKey) { public RemoteVolumeGroupController(Context context, String preferenceKey) {
super(context, preferenceKey); super(context, preferenceKey);
if (mLocalMediaManager == null) { if (mLocalMediaManager == null) {
mLocalMediaManager = new LocalMediaManager(mContext, null, null); mLocalMediaManager = new LocalMediaManager(mContext, /* packageName= */ null);
mLocalMediaManager.registerCallback(this); mLocalMediaManager.registerCallback(this);
mLocalMediaManager.startScan(); mLocalMediaManager.startScan();
} }

View File

@@ -123,6 +123,12 @@ public class SetupPreFinishDelayFragment extends InstrumentedFragment {
sHandler.postDelayed(mRunnable, MAX_DELAY_BEFORE_SETUP_FINISH); sHandler.postDelayed(mRunnable, MAX_DELAY_BEFORE_SETUP_FINISH);
} }
@Override
public void onDestroy() {
sHandler.removeCallbacks(mRunnable);
super.onDestroy();
}
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
return SettingsEnums.PRIVATE_SPACE_SETUP_PRE_FINISH; return SettingsEnums.PRIVATE_SPACE_SETUP_PRE_FINISH;

View File

@@ -29,7 +29,7 @@ import android.util.Log;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.network.SatelliteManagerUtil; import com.android.settings.network.SatelliteRepository;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
@@ -58,8 +58,8 @@ public class SimSlotChangeReceiver extends BroadcastReceiver {
if (shouldHandleSlotChange(context)) { if (shouldHandleSlotChange(context)) {
Log.d(TAG, "Checking satellite enabled status"); Log.d(TAG, "Checking satellite enabled status");
Executor executor = Executors.newSingleThreadExecutor(); Executor executor = Executors.newSingleThreadExecutor();
ListenableFuture<Boolean> satelliteEnabledFuture = SatelliteManagerUtil ListenableFuture<Boolean> satelliteEnabledFuture = new SatelliteRepository(context)
.requestIsEnabled(context, executor); .requestIsEnabled(executor);
satelliteEnabledFuture.addListener(() -> { satelliteEnabledFuture.addListener(() -> {
boolean isSatelliteEnabled = false; boolean isSatelliteEnabled = false;
try { try {

View File

@@ -21,6 +21,7 @@ import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.os.UserHandle import android.os.UserHandle
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
@@ -87,11 +88,15 @@ class AppArchiveButton(
} }
private fun ApplicationInfo.isActionButtonEnabled(): Boolean { private fun ApplicationInfo.isActionButtonEnabled(): Boolean {
return !isArchived return try {
&& userPackageManager.isAppArchivable(packageName) (!isArchived
// We apply the same device policy for both the uninstallation and archive && userPackageManager.isAppArchivable(packageName)
// button. // We apply the same device policy for both the uninstallation and archive
&& !appButtonRepository.isUninstallBlockedByAdmin(this) // button.
&& !appButtonRepository.isUninstallBlockedByAdmin(this))
} catch (e: PackageManager.NameNotFoundException) {
false
}
} }
private fun onArchiveClicked(app: ApplicationInfo) { private fun onArchiveClicked(app: ApplicationInfo) {

View File

@@ -0,0 +1,50 @@
/*
* 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.spa.network
import android.telephony.TelephonyManager
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.res.stringResource
import com.android.settings.R
import com.android.settings.network.telephony.TelephonyRepository
import com.android.settingslib.spa.widget.preference.SwitchPreference
import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@Composable
fun MobileDataSwitchingPreference(
isMobileDataEnabled: () -> Boolean?,
setMobileDataEnabled: (newEnabled: Boolean) -> Unit,
) {
val mobileDataSummary = stringResource(id = R.string.primary_sim_automatic_data_msg)
val coroutineScope = rememberCoroutineScope()
SwitchPreference(
object : SwitchPreferenceModel {
override val title = stringResource(id = R.string.mobile_data_settings_title)
override val summary = { mobileDataSummary }
override val checked = { isMobileDataEnabled() }
override val onCheckedChange: (Boolean) -> Unit = { newEnabled ->
coroutineScope.launch(Dispatchers.Default) {
setMobileDataEnabled(newEnabled)
}
}
override val changeable:() -> Boolean = {true}
}
)
}

View File

@@ -38,11 +38,12 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.res.vectorResource import androidx.compose.ui.res.vectorResource
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LifecycleRegistry
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.SubscriptionInfoListViewModel import com.android.settings.network.SubscriptionInfoListViewModel
import com.android.settings.network.telephony.MobileNetworkUtils
import com.android.settings.network.telephony.TelephonyRepository import com.android.settings.network.telephony.TelephonyRepository
import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo import com.android.settings.spa.network.PrimarySimRepository.PrimarySimInfo
import com.android.settings.wifi.WifiPickerTrackerHelper import com.android.settings.wifi.WifiPickerTrackerHelper
@@ -167,7 +168,7 @@ fun PageImpl(
defaultVoiceSubId: MutableIntState, defaultVoiceSubId: MutableIntState,
defaultSmsSubId: MutableIntState, defaultSmsSubId: MutableIntState,
defaultDataSubId: MutableIntState, defaultDataSubId: MutableIntState,
nonDds: MutableIntState nonDds: MutableIntState,
) { ) {
val selectableSubscriptionInfoList by selectableSubscriptionInfoListFlow val selectableSubscriptionInfoList by selectableSubscriptionInfoListFlow
.collectAsStateWithLifecycle(initialValue = emptyList()) .collectAsStateWithLifecycle(initialValue = emptyList())
@@ -175,22 +176,76 @@ fun PageImpl(
val stringSims = stringResource(R.string.provider_network_settings_title) val stringSims = stringResource(R.string.provider_network_settings_title)
RegularScaffold(title = stringSims) { RegularScaffold(title = stringSims) {
SimsSection(selectableSubscriptionInfoList) SimsSection(selectableSubscriptionInfoList)
MobileDataSectionImpl(defaultDataSubId,
nonDds,
)
PrimarySimSectionImpl( PrimarySimSectionImpl(
selectableSubscriptionInfoListFlow, selectableSubscriptionInfoListFlow,
defaultVoiceSubId, defaultVoiceSubId,
defaultSmsSubId, defaultSmsSubId,
defaultDataSubId, defaultDataSubId,
nonDds
) )
} }
} }
@Composable
fun MobileDataSectionImpl(
mobileDataSelectedId: MutableIntState,
nonDds: MutableIntState,
) {
val context = LocalContext.current
val localLifecycleOwner = LocalLifecycleOwner.current
val wifiPickerTrackerHelper = getWifiPickerTrackerHelper(context, localLifecycleOwner)
val subscriptionManager: SubscriptionManager? =
context.getSystemService(SubscriptionManager::class.java)
Category(title = stringResource(id = R.string.mobile_data_settings_title)) {
val isAutoDataEnabled by remember(nonDds.intValue) {
TelephonyRepository(context).isMobileDataPolicyEnabledFlow(
subId = nonDds.intValue,
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
)
}.collectAsStateWithLifecycle(initialValue = null)
val mobileDataStateChanged by remember(mobileDataSelectedId.intValue) {
TelephonyRepository(context).isDataEnabled(mobileDataSelectedId.intValue)
}.collectAsStateWithLifecycle(initialValue = false)
val coroutineScope = rememberCoroutineScope()
MobileDataSwitchingPreference(
isMobileDataEnabled = { mobileDataStateChanged },
setMobileDataEnabled = { newEnabled ->
coroutineScope.launch {
setMobileData(
context,
subscriptionManager,
wifiPickerTrackerHelper,
mobileDataSelectedId.intValue,
newEnabled
)
}
},
)
if (nonDds.intValue != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
AutomaticDataSwitchingPreference(
isAutoDataEnabled = { isAutoDataEnabled },
setAutoDataEnabled = { newEnabled ->
TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
},
)
}
}
}
@Composable @Composable
fun PrimarySimImpl( fun PrimarySimImpl(
primarySimInfo: PrimarySimInfo, primarySimInfo: PrimarySimInfo,
callsSelectedId: MutableIntState, callsSelectedId: MutableIntState,
textsSelectedId: MutableIntState, textsSelectedId: MutableIntState,
mobileDataSelectedId: MutableIntState, mobileDataSelectedId: MutableIntState,
wifiPickerTrackerHelper: WifiPickerTrackerHelper? = null,
subscriptionManager: SubscriptionManager? = subscriptionManager: SubscriptionManager? =
LocalContext.current.getSystemService(SubscriptionManager::class.java), LocalContext.current.getSystemService(SubscriptionManager::class.java),
coroutineScope: CoroutineScope = rememberCoroutineScope(), coroutineScope: CoroutineScope = rememberCoroutineScope(),
@@ -208,20 +263,15 @@ fun PrimarySimImpl(
} }
}, },
actionSetMobileData: (Int) -> Unit = { actionSetMobileData: (Int) -> Unit = {
mobileDataSelectedId.intValue = it
coroutineScope.launch { coroutineScope.launch {
// TODO: to fix the WifiPickerTracker crash when create
// the wifiPickerTrackerHelper
setDefaultData( setDefaultData(
context, context,
subscriptionManager, subscriptionManager,
null/*wifiPickerTrackerHelper*/, wifiPickerTrackerHelper,
it it
) )
} }
}, },
isAutoDataEnabled: () -> Boolean?,
setAutoDataEnabled: (newEnabled: Boolean) -> Unit,
) { ) {
CreatePrimarySimListPreference( CreatePrimarySimListPreference(
stringResource(id = R.string.primary_sim_calls_title), stringResource(id = R.string.primary_sim_calls_title),
@@ -244,8 +294,6 @@ fun PrimarySimImpl(
Icons.Outlined.DataUsage, Icons.Outlined.DataUsage,
actionSetMobileData actionSetMobileData
) )
AutomaticDataSwitchingPreference(isAutoDataEnabled, setAutoDataEnabled)
} }
@Composable @Composable
@@ -254,9 +302,11 @@ fun PrimarySimSectionImpl(
callsSelectedId: MutableIntState, callsSelectedId: MutableIntState,
textsSelectedId: MutableIntState, textsSelectedId: MutableIntState,
mobileDataSelectedId: MutableIntState, mobileDataSelectedId: MutableIntState,
nonDds: MutableIntState,
) { ) {
val context = LocalContext.current val context = LocalContext.current
val localLifecycleOwner = LocalLifecycleOwner.current
val wifiPickerTrackerHelper = getWifiPickerTrackerHelper(context, localLifecycleOwner)
val primarySimInfo = remember(subscriptionInfoListFlow) { val primarySimInfo = remember(subscriptionInfoListFlow) {
subscriptionInfoListFlow subscriptionInfoListFlow
.map { subscriptionInfoList -> .map { subscriptionInfoList ->
@@ -267,25 +317,25 @@ fun PrimarySimSectionImpl(
}.collectAsStateWithLifecycle(initialValue = null).value ?: return }.collectAsStateWithLifecycle(initialValue = null).value ?: return
Category(title = stringResource(id = R.string.primary_sim_title)) { Category(title = stringResource(id = R.string.primary_sim_title)) {
val isAutoDataEnabled by remember(nonDds.intValue) {
TelephonyRepository(context).isMobileDataPolicyEnabledFlow(
subId = nonDds.intValue,
policy = TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH
)
}.collectAsStateWithLifecycle(initialValue = null)
PrimarySimImpl( PrimarySimImpl(
primarySimInfo, primarySimInfo,
callsSelectedId, callsSelectedId,
textsSelectedId, textsSelectedId,
mobileDataSelectedId, mobileDataSelectedId,
isAutoDataEnabled = { isAutoDataEnabled }, wifiPickerTrackerHelper
setAutoDataEnabled = { newEnabled ->
TelephonyRepository(context).setAutomaticData(nonDds.intValue, newEnabled)
},
) )
} }
} }
private fun getWifiPickerTrackerHelper(
context: Context,
lifecycleOwner: LifecycleOwner
): WifiPickerTrackerHelper {
return WifiPickerTrackerHelper(
LifecycleRegistry(lifecycleOwner), context,
null /* WifiPickerTrackerCallback */
)
}
private fun Context.defaultVoiceSubscriptionFlow(): Flow<Int> = private fun Context.defaultVoiceSubscriptionFlow(): Flow<Int> =
merge( merge(
flowOf(null), // kick an initial value flowOf(null), // kick an initial value
@@ -334,19 +384,28 @@ suspend fun setDefaultData(
subscriptionManager: SubscriptionManager?, subscriptionManager: SubscriptionManager?,
wifiPickerTrackerHelper: WifiPickerTrackerHelper?, wifiPickerTrackerHelper: WifiPickerTrackerHelper?,
subId: Int subId: Int
): Unit =
setMobileData(
context,
subscriptionManager,
wifiPickerTrackerHelper,
subId,
true
)
suspend fun setMobileData(
context: Context,
subscriptionManager: SubscriptionManager?,
wifiPickerTrackerHelper: WifiPickerTrackerHelper?,
subId: Int,
enabled: Boolean,
): Unit = ): Unit =
withContext(Dispatchers.Default) { withContext(Dispatchers.Default) {
subscriptionManager?.setDefaultDataSubId(subId) Log.d(NetworkCellularGroupProvider.name, "setMobileData: $enabled")
Log.d(NetworkCellularGroupProvider.name, "setMobileDataEnabled: true") if (enabled) {
MobileNetworkUtils.setMobileDataEnabled( Log.d(NetworkCellularGroupProvider.name, "setDefaultData: [$subId]")
context, subscriptionManager?.setDefaultDataSubId(subId)
subId,
true /* enabled */,
true /* disableOtherSubscriptions */
)
if (wifiPickerTrackerHelper != null
&& !wifiPickerTrackerHelper.isCarrierNetworkProvisionEnabled(subId)
) {
wifiPickerTrackerHelper.setCarrierNetworkEnabled(true)
} }
TelephonyRepository(context)
.setMobileData(subId, enabled, wifiPickerTrackerHelper)
} }

View File

@@ -102,18 +102,21 @@ fun SimOnboardingPrimarySimImpl(
mobileDataSelectedId = mobileDataSelectedId, mobileDataSelectedId = mobileDataSelectedId,
actionSetCalls = { actionSetCalls = {
callsSelectedId.intValue = it callsSelectedId.intValue = it
onboardingService.targetPrimarySimCalls = it}, onboardingService.targetPrimarySimCalls = it
},
actionSetTexts = { actionSetTexts = {
textsSelectedId.intValue = it textsSelectedId.intValue = it
onboardingService.targetPrimarySimTexts = it}, onboardingService.targetPrimarySimTexts = it
},
actionSetMobileData = { actionSetMobileData = {
mobileDataSelectedId.intValue = it mobileDataSelectedId.intValue = it
onboardingService.targetPrimarySimMobileData = it}, onboardingService.targetPrimarySimMobileData = it
isAutoDataEnabled = { isAutoDataEnabled }, }
)
AutomaticDataSwitchingPreference(isAutoDataEnabled = { isAutoDataEnabled },
setAutoDataEnabled = { newEnabled -> setAutoDataEnabled = { newEnabled ->
onboardingService.targetPrimarySimAutoDataSwitch.value = newEnabled onboardingService.targetPrimarySimAutoDataSwitch.value = newEnabled
}, })
)
} }
} }

View File

@@ -53,7 +53,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule; import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.LooperMode;
import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowApplication;
import java.util.ArrayList; import java.util.ArrayList;
@@ -63,7 +62,6 @@ import java.util.List;
import java.util.Set; import java.util.Set;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(LooperMode.Mode.LEGACY)
public final class InstalledAppCounterTest { public final class InstalledAppCounterTest {
@Rule @Rule

View File

@@ -79,7 +79,6 @@ import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment; import org.robolectric.RuntimeEnvironment;
import org.robolectric.android.controller.ActivityController; import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.LooperMode;
import org.robolectric.util.ReflectionHelpers; import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList; import java.util.ArrayList;
@@ -88,7 +87,6 @@ import java.util.concurrent.atomic.AtomicReference;
@Ignore("b/295325503") @Ignore("b/295325503")
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@LooperMode(LooperMode.Mode.LEGACY)
public class FingerprintEnrollEnrollingTest { public class FingerprintEnrollEnrollingTest {
private static final String ENROLL_PROGRESS_COLOR_LIGHT = "#699FF3"; private static final String ENROLL_PROGRESS_COLOR_LIGHT = "#699FF3";
private static final String ENROLL_PROGRESS_COLOR_DARK = "#7DA7F1"; private static final String ENROLL_PROGRESS_COLOR_DARK = "#7DA7F1";

View File

@@ -35,12 +35,14 @@ import android.bluetooth.BluetoothCodecType;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothProfile;
import android.content.Context; import android.content.Context;
import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import androidx.preference.ListPreference; import androidx.preference.ListPreference;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import com.android.settings.development.BluetoothA2dpConfigStore; import com.android.settings.development.BluetoothA2dpConfigStore;
import com.android.settings.development.Flags;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before; import org.junit.Before;
@@ -57,7 +59,6 @@ import java.util.List;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
public class BluetoothCodecListPreferenceControllerTest { public class BluetoothCodecListPreferenceControllerTest {
private static final String DEVICE_ADDRESS = "00:11:22:33:44:55"; private static final String DEVICE_ADDRESS = "00:11:22:33:44:55";
@Mock private BluetoothA2dp mBluetoothA2dp; @Mock private BluetoothA2dp mBluetoothA2dp;
@@ -245,6 +246,7 @@ public class BluetoothCodecListPreferenceControllerTest {
} }
@Test @Test
@RequiresFlagsEnabled(Flags.FLAG_A2DP_OFFLOAD_CODEC_EXTENSIBILITY_SETTINGS)
public void onPreferenceChange_notifyPreference() { public void onPreferenceChange_notifyPreference() {
assertFalse( assertFalse(
mController.onPreferenceChange( mController.onPreferenceChange(

View File

@@ -1,71 +0,0 @@
/*
* Copyright (C) 2019 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.language;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.view.inputmethod.InputMethodInfo;
import com.android.settings.testutils.shadow.ShadowInputMethodManagerWithMethodList;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = ShadowInputMethodManagerWithMethodList.class)
public class LanguageAndInputPreferenceControllerTest {
private Context mContext;
@Before
public void setUp() {
mContext = spy(RuntimeEnvironment.application);
}
@Test
public void getSummary_shouldSetToCurrentImeName() {
final ComponentName componentName = new ComponentName("name1", "cls");
final ContentResolver cr = mContext.getContentResolver();
Settings.Secure.putString(cr, Settings.Secure.DEFAULT_INPUT_METHOD,
componentName.flattenToString());
final List<InputMethodInfo> imis = new ArrayList<>();
imis.add(mock(InputMethodInfo.class));
when(imis.get(0).getPackageName()).thenReturn("name1");
when(imis.get(0).loadLabel(any())).thenReturn("label");
ShadowInputMethodManagerWithMethodList.getShadow().setInputMethodList(imis);
final LanguageAndInputPreferenceController controller =
new LanguageAndInputPreferenceController(mContext, "key");
assertThat(controller.getSummary().toString()).contains("label");
}
}

View File

@@ -1,185 +0,0 @@
/*
* Copyright (C) 2016 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.language;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.res.Resources;
import android.hardware.input.InputManager;
import android.os.UserManager;
import android.util.FeatureFlagUtils;
import android.view.autofill.AutofillManager;
import android.view.inputmethod.InputMethodManager;
import android.view.textservice.TextServicesManager;
import androidx.lifecycle.LifecycleObserver;
import com.android.settings.R;
import com.android.settings.testutils.XmlTestUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.ArrayList;
import java.util.List;
@RunWith(RobolectricTestRunner.class)
public class LanguageAndInputSettingsTest {
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Activity mActivity;
@Mock
private InputManager mIm;
@Mock
private InputMethodManager mImm;
@Mock
private DevicePolicyManager mDpm;
@Mock
private AutofillManager mAutofillManager;
private TestFragment mFragment;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mock(UserManager.class));
when(mActivity.getSystemService(Context.INPUT_SERVICE))
.thenReturn(mock(InputManager.class));
when(mActivity.getSystemService(Context.INPUT_SERVICE)).thenReturn(mIm);
when(mActivity.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE))
.thenReturn(mock(TextServicesManager.class));
when(mActivity.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(mDpm);
when(mActivity.getSystemService(Context.INPUT_METHOD_SERVICE)).thenReturn(mImm);
when((Object) mActivity.getSystemService(AutofillManager.class))
.thenReturn(mAutofillManager);
mFragment = new TestFragment(mActivity);
}
@Test
public void testGetPreferenceScreenResId() {
assertThat(mFragment.getPreferenceScreenResId()).isEqualTo(R.xml.language_and_input);
}
@Test
public void testGetPreferenceControllers_shouldRegisterLifecycleObservers() {
final List<AbstractPreferenceController> controllers =
mFragment.createPreferenceControllers(mActivity);
int lifecycleObserverCount = 0;
for (AbstractPreferenceController controller : controllers) {
if (controller instanceof LifecycleObserver) {
lifecycleObserverCount++;
}
}
verify(mFragment.getSettingsLifecycle(), times(lifecycleObserverCount))
.addObserver(any(LifecycleObserver.class));
}
@Test
public void testGetPreferenceControllers_shouldAllBeCreated() {
final List<AbstractPreferenceController> controllers =
mFragment.createPreferenceControllers(mActivity);
assertThat(controllers.isEmpty()).isFalse();
}
@Test
public void testNonIndexableKeys_existInXmlLayout() {
final Context context = spy(RuntimeEnvironment.application);
final Resources res = spy(RuntimeEnvironment.application.getResources());
final InputManager inputManager = mock(InputManager.class);
final TextServicesManager textServicesManager = mock(TextServicesManager.class);
FeatureFlagUtils.setEnabled(context, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI, false);
when(inputManager.getInputDeviceIds()).thenReturn(new int[0]);
doReturn(inputManager).when(context).getSystemService(Context.INPUT_SERVICE);
doReturn(textServicesManager).when(context)
.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
doReturn(res).when(context).getResources();
doReturn(false).when(res)
.getBoolean(com.android.internal.R.bool.config_supportSystemNavigationKeys);
final List<String> niks =
LanguageAndInputSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(context);
LanguageAndInputSettings settings = new LanguageAndInputSettings();
final int xmlId = settings.getPreferenceScreenResId();
final List<String> keys = XmlTestUtils.getKeysFromPreferenceXml(context, xmlId);
assertThat(keys).containsAtLeastElementsIn(niks);
}
@Test
public void testPreferenceControllers_getPreferenceKeys_existInPreferenceScreen() {
final Context context = spy(RuntimeEnvironment.application);
final TextServicesManager textServicesManager = mock(TextServicesManager.class);
doReturn(textServicesManager).when(context)
.getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
final LanguageAndInputSettings fragment = new LanguageAndInputSettings();
final List<String> preferenceScreenKeys =
XmlTestUtils.getKeysFromPreferenceXml(context, fragment.getPreferenceScreenResId());
final List<String> preferenceKeys = new ArrayList<>();
for (AbstractPreferenceController controller : fragment.createPreferenceControllers(context)) {
preferenceKeys.add(controller.getPreferenceKey());
}
assertThat(preferenceScreenKeys).containsAtLeastElementsIn(preferenceKeys);
}
/**
* Test fragment to expose lifecycle and context so we can verify behavior for observables.
*/
public static class TestFragment extends LanguageAndInputSettings {
private Lifecycle mLifecycle;
private Context mContext;
public TestFragment(Context context) {
mContext = context;
mLifecycle = mock(Lifecycle.class);
}
@Override
public Context getContext() {
return mContext;
}
@Override
public Lifecycle getSettingsLifecycle() {
if (mLifecycle == null) {
return super.getSettingsLifecycle();
}
return mLifecycle;
}
}
}

View File

@@ -20,10 +20,12 @@ import android.content.Context
import android.os.OutcomeReceiver import android.os.OutcomeReceiver
import android.telephony.satellite.SatelliteManager import android.telephony.satellite.SatelliteManager
import android.telephony.satellite.SatelliteManager.SatelliteException import android.telephony.satellite.SatelliteManager.SatelliteException
import android.telephony.satellite.SatelliteModemStateCallback
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import com.android.settings.network.SatelliteManagerUtil.requestIsEnabled import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.ListenableFuture import com.google.common.util.concurrent.ListenableFuture
import java.util.concurrent.Executor import java.util.concurrent.Executor
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertFalse import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue import org.junit.Assert.assertTrue
@@ -42,7 +44,7 @@ import org.robolectric.RobolectricTestRunner
@RunWith(RobolectricTestRunner::class) @RunWith(RobolectricTestRunner::class)
class SatelliteManagerUtilTest { class SatelliteRepositoryTest {
@JvmField @JvmField
@Rule @Rule
@@ -57,10 +59,15 @@ class SatelliteManagerUtilTest {
@Mock @Mock
private lateinit var mockExecutor: Executor private lateinit var mockExecutor: Executor
private lateinit var repository: SatelliteRepository
@Before @Before
fun setUp() { fun setUp() {
`when`(this.spyContext.getSystemService(SatelliteManager::class.java)) `when`(this.spyContext.getSystemService(SatelliteManager::class.java))
.thenReturn(mockSatelliteManager) .thenReturn(mockSatelliteManager)
repository = SatelliteRepository(spyContext)
} }
@Test @Test
@@ -78,7 +85,7 @@ class SatelliteManagerUtilTest {
} }
val result: ListenableFuture<Boolean> = val result: ListenableFuture<Boolean> =
requestIsEnabled(spyContext, mockExecutor) repository.requestIsEnabled(mockExecutor)
assertTrue(result.get()) assertTrue(result.get())
} }
@@ -98,7 +105,7 @@ class SatelliteManagerUtilTest {
} }
val result: ListenableFuture<Boolean> = val result: ListenableFuture<Boolean> =
requestIsEnabled(spyContext, mockExecutor) repository.requestIsEnabled(mockExecutor)
assertFalse(result.get()) assertFalse(result.get())
} }
@@ -117,7 +124,7 @@ class SatelliteManagerUtilTest {
null null
} }
val result = requestIsEnabled(spyContext, mockExecutor) val result = repository.requestIsEnabled(mockExecutor)
assertFalse(result.get()) assertFalse(result.get())
} }
@@ -126,8 +133,52 @@ class SatelliteManagerUtilTest {
fun requestIsEnabled_nullSatelliteManager() = runBlocking { fun requestIsEnabled_nullSatelliteManager() = runBlocking {
`when`(spyContext.getSystemService(SatelliteManager::class.java)).thenReturn(null) `when`(spyContext.getSystemService(SatelliteManager::class.java)).thenReturn(null)
val result: ListenableFuture<Boolean> = requestIsEnabled(spyContext, mockExecutor) val result: ListenableFuture<Boolean> = repository.requestIsEnabled(mockExecutor)
assertFalse(result.get()) assertFalse(result.get())
} }
@Test
fun getIsModemEnabledFlow_isSatelliteEnabledState() = runBlocking {
`when`(
mockSatelliteManager.registerForModemStateChanged(
any(),
any()
)
).thenAnswer { invocation ->
val callback = invocation.getArgument<SatelliteModemStateCallback>(1)
callback.onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED)
SatelliteManager.SATELLITE_RESULT_SUCCESS
}
val flow = repository.getIsModemEnabledFlow()
assertThat(flow.first()).isTrue()
}
@Test
fun getIsModemEnabledFlow_isSatelliteDisabledState() = runBlocking {
`when`(
mockSatelliteManager.registerForModemStateChanged(
any(),
any()
)
).thenAnswer { invocation ->
val callback = invocation.getArgument<SatelliteModemStateCallback>(1)
callback.onSatelliteModemStateChanged(SatelliteManager.SATELLITE_MODEM_STATE_OFF)
SatelliteManager.SATELLITE_RESULT_SUCCESS
}
val flow = repository.getIsModemEnabledFlow()
assertThat(flow.first()).isFalse()
}
@Test
fun getIsModemEnabledFlow_nullSatelliteManager() = runBlocking {
`when`(spyContext.getSystemService(SatelliteManager::class.java)).thenReturn(null)
val flow = repository.getIsModemEnabledFlow()
assertThat(flow.first()).isFalse()
}
} }

View File

@@ -91,6 +91,30 @@ class TelephonyRepositoryTest {
.setMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true) .setMobileDataPolicyEnabled(TelephonyManager.MOBILE_DATA_POLICY_AUTO_DATA_SWITCH, true)
} }
@Test
fun isDataEnabled_invalidSub_returnFalse() = runBlocking {
val state = repository.isDataEnabled(
subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID,
)
assertThat(state.firstWithTimeoutOrNull()).isFalse()
}
@Test
fun isDataEnabled_validSub_returnPolicyState() = runBlocking {
mockTelephonyManager.stub {
on {
isDataEnabledForReason(TelephonyManager.DATA_ENABLED_REASON_USER)
} doReturn true
}
val state = repository.isDataEnabled(
subId = SUB_ID,
)
assertThat(state.firstWithTimeoutOrNull()).isTrue()
}
@Test @Test
fun telephonyCallbackFlow_callbackRegistered() = runBlocking { fun telephonyCallbackFlow_callbackRegistered() = runBlocking {
val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) { val flow = context.telephonyCallbackFlow<Unit>(SUB_ID) {

View File

@@ -109,6 +109,19 @@ class AppArchiveButtonTest {
assertThat(enabledActionButton.enabled).isFalse() assertThat(enabledActionButton.enabled).isFalse()
} }
@Test
fun appArchiveButton_whenPackageIsNotFound_isDisabled() {
val app = ApplicationInfo().apply {
packageName = PACKAGE_NAME
isArchived = false
}
whenever(userPackageManager.isAppArchivable(app.packageName)).thenThrow(PackageManager.NameNotFoundException())
val actionButton = setContent(app)
assertThat(actionButton.enabled).isFalse()
}
@Test @Test
fun appArchiveButton_displaysRightTextAndIcon() { fun appArchiveButton_displaysRightTextAndIcon() {
val app = ApplicationInfo().apply { val app = ApplicationInfo().apply {

View File

@@ -16,71 +16,32 @@
package com.android.settings.language; package com.android.settings.language;
import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.util.FeatureFlagUtils;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.Settings; import com.android.settings.Settings;
import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
public class LanguagePreferenceControllerTest { public class LanguagePreferenceControllerTest {
private boolean mCacheFeatureFlagSwitch = false;
private Context mContext; private Context mContext;
private LanguagePreferenceController mController; private LanguagePreferenceController mController;
@Before @Before
public void setup() { public void setup() {
mContext = ApplicationProvider.getApplicationContext(); mContext = ApplicationProvider.getApplicationContext();
mCacheFeatureFlagSwitch =
FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI);
mController = new LanguagePreferenceController(mContext, "key"); mController = new LanguagePreferenceController(mContext, "key");
}
@After
public void tearDown() {
FeatureFlagUtils.setEnabled(
mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI, mCacheFeatureFlagSwitch);
}
@Test
public void getAvailabilityStatus_featureFlagOff_returnUnavailable() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI,
false);
int result = mController.getAvailabilityStatus();
assertEquals(CONDITIONALLY_UNAVAILABLE, result);
}
@Test
public void getAvailabilityStatus_featureFlagOff_LanguageAndInputSettingsActivityEnabled() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI,
false);
mController.getAvailabilityStatus();
assertTrue(isActivityEnable(mContext, Settings.LanguageAndInputSettingsActivity.class));
assertFalse(isActivityEnable(mContext, Settings.LanguageSettingsActivity.class));
} }
@Test @Test
public void getAvailabilityStatus_featureFlagOff_LanguageAndInputSettingsActivitydisabled() { public void getAvailabilityStatus_featureFlagOff_LanguageAndInputSettingsActivitydisabled() {
FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SETTINGS_NEW_KEYBOARD_UI,
true);
mController.getAvailabilityStatus(); mController.getAvailabilityStatus();
assertFalse(isActivityEnable(mContext, Settings.LanguageAndInputSettingsActivity.class)); assertFalse(isActivityEnable(mContext, Settings.LanguageAndInputSettingsActivity.class));