Snap for 13256841 from 081fab1330 to 25Q2-release

Change-Id: I36755cf3e7b0e6de77eb961c135989c6cca80050
This commit is contained in:
Android Build Coastguard Worker
2025-03-21 20:22:28 -07:00
36 changed files with 827 additions and 81 deletions

View File

@@ -0,0 +1,25 @@
<!--
Copyright (C) 2025 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="960"
android:viewportWidth="960"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M160,800Q127,800 103.5,776.5Q80,753 80,720L80,240Q80,207 103.5,183.5Q127,160 160,160L800,160Q833,160 856.5,183.5Q880,207 880,240L880,720Q880,753 856.5,776.5Q833,800 800,800L160,800ZM260,600L306,600L306,360L270,360L200,410L224,446L260,420L260,600ZM384,600L540,600L540,560L446,560L444,558Q465,538 478.5,524Q492,510 500,502Q518,484 527,466Q536,448 536,428Q536,399 514,379.5Q492,360 458,360Q432,360 411,375Q390,390 382,414L422,430Q427,417 436.5,409.5Q446,402 458,402Q473,402 482.5,410Q492,418 492,430Q492,441 488,450.5Q484,460 470,474Q459,485 438,506Q417,527 384,560L384,600ZM680,600Q716,600 738,580Q760,560 760,528Q760,510 750,496Q740,482 722,474L722,472Q736,464 744,451.5Q752,439 752,422Q752,395 731,377.5Q710,360 678,360Q653,360 631.5,374.5Q610,389 604,410L644,426Q648,414 657,407Q666,400 678,400Q691,400 699.5,407.5Q708,415 708,426Q708,440 698,448Q688,456 672,456L654,456L654,496L674,496Q694,496 705,504Q716,512 716,526Q716,539 705,548.5Q694,558 680,558Q663,558 654,550.5Q645,543 638,524L598,540Q605,569 626.5,584.5Q648,600 680,600ZM160,720L800,720Q800,720 800,720Q800,720 800,720L800,240Q800,240 800,240Q800,240 800,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720ZM160,720Q160,720 160,720Q160,720 160,720L160,240Q160,240 160,240Q160,240 160,240L160,240Q160,240 160,240Q160,240 160,240L160,720Q160,720 160,720Q160,720 160,720Z" />
</vector>

View File

@@ -1358,6 +1358,10 @@
<string name="lock_screen_pattern_skip_fingerprint_title">Skip setup for pattern and fingerprint?</string> <string name="lock_screen_pattern_skip_fingerprint_title">Skip setup for pattern and fingerprint?</string>
<!-- Title of dialog shown when the user tries to skip setting up a pattern, warning them of potential consequences of not doing so [CHAR LIMIT=48]--> <!-- Title of dialog shown when the user tries to skip setting up a pattern, warning them of potential consequences of not doing so [CHAR LIMIT=48]-->
<string name="lock_screen_pattern_skip_biometrics_title">Skip setup for pattern, face, and fingerprint?</string> <string name="lock_screen_pattern_skip_biometrics_title">Skip setup for pattern, face, and fingerprint?</string>
<!-- Accessibility action label for resuming animation -->
<string name="resume_animation">Resume animation</string>
<!-- Accessibility action label for pausing animation -->
<string name="pause_animation">Pause animation</string>
<!-- Button text to setup screen lock in onboard dialog [CHAR LIMIT=34] --> <!-- Button text to setup screen lock in onboard dialog [CHAR LIMIT=34] -->
<string name="security_settings_fingerprint_enroll_setup_screen_lock">Set up screen lock</string> <string name="security_settings_fingerprint_enroll_setup_screen_lock">Set up screen lock</string>
@@ -5934,6 +5938,10 @@
<string name="accessibility_hearing_device_pairing_page_title">Pair hearing device</string> <string name="accessibility_hearing_device_pairing_page_title">Pair hearing device</string>
<!-- Subtitle for the pair hearing device page. [CHAR LIMIT=NONE] --> <!-- Subtitle for the pair hearing device page. [CHAR LIMIT=NONE] -->
<string name="accessibility_hearing_device_pairing_intro">You can pair ASHA and LE Audio hearing devices on this page. Make sure your hearing device is turned on and ready to pair.</string> <string name="accessibility_hearing_device_pairing_intro">You can pair ASHA and LE Audio hearing devices on this page. Make sure your hearing device is turned on and ready to pair.</string>
<!-- Subtitle for the pair hearing device page. This string is for device that only supports ASHA hearing aids. [CHAR LIMIT=NONE] -->
<string name="accessibility_hearing_device_pairing_asha_only_intro">You can pair ASHA hearing devices on this page. Make sure your hearing device is turned on and ready to pair.</string>
<!-- Subtitle for the pair hearing device page. This string is for device that only supports LE Audio hearing aids. [CHAR LIMIT=NONE] -->
<string name="accessibility_hearing_device_pairing_hap_only_intro">You can pair LE Audio hearing devices on this page. Make sure your hearing device is turned on and ready to pair.</string>
<!-- Title for the preference category containing the list of the available hearing during and after bluetooth scanning devices. [CHAR LIMIT=30] --> <!-- Title for the preference category containing the list of the available hearing during and after bluetooth scanning devices. [CHAR LIMIT=30] -->
<string name="accessibility_found_hearing_devices">Available hearing devices</string> <string name="accessibility_found_hearing_devices">Available hearing devices</string>
<!-- Title for the preference category containing the all bluetooth devices during and after bluetooth scanning devices. Used when people can not find their hearing device in hearing device pairing list. [CHAR LIMIT=45] --> <!-- Title for the preference category containing the all bluetooth devices during and after bluetooth scanning devices. Used when people can not find their hearing device in hearing device pairing list. [CHAR LIMIT=45] -->
@@ -12764,6 +12772,10 @@ Data usage charges may apply.</string>
<string name="title_satellite_supported_app_list_entry">see all apps</string> <string name="title_satellite_supported_app_list_entry">see all apps</string>
<!-- Title for a page of apps list page with Satellite service supported. [CHAR LIMIT=60] --> <!-- Title for a page of apps list page with Satellite service supported. [CHAR LIMIT=60] -->
<string name="title_satellite_supported_app_list_page">Supported apps on your phone</string> <string name="title_satellite_supported_app_list_page">Supported apps on your phone</string>
<!-- Title for showing a dialog to notify user sim restriction. [CHAR LIMIT=60] -->
<string name="title_satellite_dialog_for_sim_restriction">Can\u2019t add a SIM</string>
<!-- Description for showing a dialog to notify user sim restriction. [CHAR LIMIT=NONE] -->
<string name="description_satellite_dialog_for_sim_restriction">End the satellite connection before you add a SIM</string>
<!-- Title for Apn settings in mobile network settings [CHAR LIMIT=60] --> <!-- Title for Apn settings in mobile network settings [CHAR LIMIT=60] -->
<string name="mobile_network_apn_title">Access Point Names</string> <string name="mobile_network_apn_title">Access Point Names</string>

View File

@@ -20,8 +20,10 @@
android:title="@string/bluetooth_pairing_pref_title"> android:title="@string/bluetooth_pairing_pref_title">
<com.android.settingslib.widget.TopIntroPreference <com.android.settingslib.widget.TopIntroPreference
android:key="hearing_device_pairing_intro"
settings:searchable="false" settings:searchable="false"
android:title="@string/accessibility_hearing_device_pairing_intro" /> android:title="@string/accessibility_hearing_device_pairing_intro"
settings:controller="com.android.settings.accessibility.HearingDevicePairingIntroPreferenceController"/>
<com.android.settings.bluetooth.BluetoothProgressCategory <com.android.settings.bluetooth.BluetoothProgressCategory
android:key="available_hearing_devices" android:key="available_hearing_devices"

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2025 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.accessibility;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.google.common.annotations.VisibleForTesting;
public class HearingDevicePairingIntroPreferenceController extends BasePreferenceController {
private final HearingAidHelper mHelper;
public HearingDevicePairingIntroPreferenceController(
@NonNull Context context,
@NonNull String preferenceKey) {
super(context, preferenceKey);
mHelper = new HearingAidHelper(context);
}
@VisibleForTesting
public HearingDevicePairingIntroPreferenceController(
@NonNull Context context,
@NonNull String preferenceKey,
@NonNull HearingAidHelper hearingAidHelper) {
super(context, preferenceKey);
mHelper = hearingAidHelper;
}
@Override
public int getAvailabilityStatus() {
return mHelper.isHearingAidSupported() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
public void displayPreference(@NonNull PreferenceScreen screen) {
super.displayPreference(screen);
final Preference pairingIntroPreference = screen.findPreference(getPreferenceKey());
final boolean isAshaProfileSupported = mHelper.isAshaProfileSupported();
final boolean isHapClientProfileSupported = mHelper.isHapClientProfileSupported();
if (isAshaProfileSupported && isHapClientProfileSupported) {
pairingIntroPreference.setTitle(
mContext.getString(R.string.accessibility_hearing_device_pairing_intro));
} else if (isAshaProfileSupported) {
pairingIntroPreference.setTitle(
mContext.getString(
R.string.accessibility_hearing_device_pairing_asha_only_intro));
} else if (isHapClientProfileSupported) {
pairingIntroPreference.setTitle(
mContext.getString(
R.string.accessibility_hearing_device_pairing_hap_only_intro));
} else {
// Intentionally blank, getAvailabilityStatus() should handle visibility for
// none-supported case.
}
}
}

View File

@@ -73,7 +73,7 @@ public interface FingerprintFeatureProvider {
default FingerprintExtPreferencesProvider getExtPreferenceProvider( default FingerprintExtPreferencesProvider getExtPreferenceProvider(
@NonNull Context context @NonNull Context context
) { ) {
return new FingerprintExtPreferencesProvider(); return new FingerprintExtPreferencesProvider(context);
} }
/** /**

View File

@@ -468,12 +468,10 @@ public class FingerprintSettings extends SubSettings {
* Add new preferences from FingerprintExtPreferencesProvider * Add new preferences from FingerprintExtPreferencesProvider
*/ */
public void setupExtFingerprintPreferences() { public void setupExtFingerprintPreferences() {
final FingerprintExtPreferencesProvider preferencesProvider = FingerprintExtPreferencesProvider preferencesProvider = getExtPreferenceProvider();
FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider()
.getExtPreferenceProvider(requireContext());
for (int index = 0; index < preferencesProvider.getSize(); ++index) { for (int index = 0; index < preferencesProvider.getSize(); ++index) {
final RestrictedPreference preference = preferencesProvider.newPreference( final RestrictedPreference preference = preferencesProvider.newPreference(
index, this::inflateFromResource, requireContext()); index, this::inflateFromResource);
if (preference == null || findPreference(preference.getKey()) != null) { if (preference == null || findPreference(preference.getKey()) != null) {
continue; continue;
} }
@@ -485,6 +483,12 @@ public class FingerprintSettings extends SubSettings {
} }
} }
@NonNull
private FingerprintExtPreferencesProvider getExtPreferenceProvider() {
return FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider()
.getExtPreferenceProvider(requireContext());
}
/** /**
* *
*/ */
@@ -748,7 +752,8 @@ public class FingerprintSettings extends SubSettings {
// This needs to be after setting ids, otherwise // This needs to be after setting ids, otherwise
// |mRequireScreenOnToAuthPreferenceController.isChecked| is always checking the primary // |mRequireScreenOnToAuthPreferenceController.isChecked| is always checking the primary
// user instead of the user with |mUserId|. // user instead of the user with |mUserId|.
if (isSfps() || (screenOffUnlockUdfps() && isScreenOffUnlcokSupported())) { if (isSfps() || (screenOffUnlockUdfps() && isScreenOffUnlcokSupported())
|| getExtPreferenceProvider().getSize() > 0) {
scrollToPreference(fpPrefKey); scrollToPreference(fpPrefKey);
addFingerprintUnlockCategory(); addFingerprintUnlockCategory();
} }
@@ -1266,6 +1271,16 @@ public class FingerprintSettings extends SubSettings {
} }
} }
if (mFingerprintUnlockCategoryPreferenceController == null
&& getExtPreferenceProvider().getSize() > 0 && controllers != null) {
for (AbstractPreferenceController controller : controllers) {
if (KEY_FINGERPRINT_UNLOCK_CATEGORY.equals(controller.getPreferenceKey())) {
mFingerprintUnlockCategoryPreferenceController =
(FingerprintUnlockCategoryController) controller;
}
}
}
return controllers; return controllers;
} }
@@ -1654,7 +1669,10 @@ public class FingerprintSettings extends SubSettings {
private static final String KEY_USER_ID = "user_id"; private static final String KEY_USER_ID = "user_id";
private static final String KEY_SENSOR_PROPERTIES = "sensor_properties"; private static final String KEY_SENSOR_PROPERTIES = "sensor_properties";
private static final String EXTRA_FAILURE_COUNT = "failure_count";
private static final int MAX_FAILURE_COUNT = 3;
private int mUserId; private int mUserId;
private int mFailureCount;
private @Nullable CancellationSignal mCancellationSignal; private @Nullable CancellationSignal mCancellationSignal;
private @Nullable FingerprintSensorPropertiesInternal mSensorPropertiesInternal; private @Nullable FingerprintSensorPropertiesInternal mSensorPropertiesInternal;
@@ -1663,6 +1681,9 @@ public class FingerprintSettings extends SubSettings {
@NonNull LayoutInflater inflater, @NonNull LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) { @Nullable Bundle savedInstanceState) {
if (savedInstanceState != null) {
mFailureCount = savedInstanceState.getInt(EXTRA_FAILURE_COUNT, 0);
}
return inflater.inflate( return inflater.inflate(
R.layout.fingerprint_check_enrolled_dialog, container, false); R.layout.fingerprint_check_enrolled_dialog, container, false);
} }
@@ -1682,12 +1703,22 @@ public class FingerprintSettings extends SubSettings {
final UdfpsCheckEnrolledView v = final UdfpsCheckEnrolledView v =
dialog.findViewById(R.id.udfps_check_enrolled_view); dialog.findViewById(R.id.udfps_check_enrolled_view);
v.setSensorProperties(mSensorPropertiesInternal); v.setSensorProperties(mSensorPropertiesInternal);
v.setOnTouchListener((view, event) -> {
Log.d(TAG, "CheckEnrollDialog dismissed: touch outside");
dialog.dismiss();
return false;
});
}); });
} }
return dialog; return dialog;
} }
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(EXTRA_FAILURE_COUNT, mFailureCount);
}
@Override @Override
public void onStart() { public void onStart() {
super.onStart(); super.onStart();
@@ -1752,6 +1783,11 @@ public class FingerprintSettings extends SubSettings {
message.postDelayed(() -> { message.postDelayed(() -> {
message.setText(R.string.fingerprint_check_enroll_touch_sensor); message.setText(R.string.fingerprint_check_enroll_touch_sensor);
}, 2000); }, 2000);
mFailureCount++;
if (mFailureCount >= MAX_FAILURE_COUNT) {
Log.d(TAG, "CheckEnrollDialog dismissed: failed 3 times");
dialog.dismiss();
}
} }
}, },
null /* handler */, null /* handler */,

View File

@@ -24,6 +24,7 @@ import android.util.AttributeSet;
import android.util.Log; import android.util.Log;
import android.util.RotationUtils; import android.util.RotationUtils;
import android.view.DisplayInfo; import android.view.DisplayInfo;
import android.view.MotionEvent;
import android.view.Surface; import android.view.Surface;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
@@ -61,6 +62,13 @@ public class UdfpsCheckEnrolledView extends RelativeLayout {
super.onFinishInflate(); super.onFinishInflate();
mFingerprintView = findViewById(R.id.udfps_fingerprint_sensor_view); mFingerprintView = findViewById(R.id.udfps_fingerprint_sensor_view);
mFingerprintView.setImageDrawable(mFingerprintDrawable); mFingerprintView.setImageDrawable(mFingerprintDrawable);
mFingerprintView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "Fingerprint view touched!");
return true;
}
return false;
});
} }
/** /**

View File

@@ -27,14 +27,13 @@ import com.android.settingslib.RestrictedPreference
* *
* @see com.android.settings.biometrics.fingerprint.FingerprintSettings * @see com.android.settings.biometrics.fingerprint.FingerprintSettings
*/ */
open class FingerprintExtPreferencesProvider { open class FingerprintExtPreferencesProvider(protected val context: Context) {
open val size: Int = 0 open val size: Int = 0
open fun newPreference( open fun newPreference(
index: Int, index: Int,
inflater: PreferenceInflater, inflater: PreferenceInflater,
context: Context
): RestrictedPreference? = null ): RestrictedPreference? = null
interface PreferenceInflater { interface PreferenceInflater {

View File

@@ -60,6 +60,8 @@ import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.Lifecycle;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -417,13 +419,17 @@ public class BluetoothDeviceDetailsFragment extends BluetoothDetailsConfigurable
@Nullable @Nullable
private List<String> generateDisplayedPreferenceKeys(boolean bondingLoss) { private List<String> generateDisplayedPreferenceKeys(boolean bondingLoss) {
if (bondingLoss) { if (bondingLoss) {
return List.of( ImmutableList.Builder<String> visibleKeys = new ImmutableList.Builder<>();
use(BluetoothDetailsBannerController.class).getPreferenceKey(), visibleKeys
use(AdvancedBluetoothDetailsHeaderController.class).getPreferenceKey(), .add(use(BluetoothDetailsBannerController.class).getPreferenceKey())
use(BluetoothDetailsHeaderController.class).getPreferenceKey(), .add(use(AdvancedBluetoothDetailsHeaderController.class).getPreferenceKey())
use(LeAudioBluetoothDetailsHeaderController.class).getPreferenceKey(), .add(use(BluetoothDetailsHeaderController.class).getPreferenceKey())
use(BluetoothDetailsButtonsController.class).getPreferenceKey(), .add(use(LeAudioBluetoothDetailsHeaderController.class).getPreferenceKey())
use(BluetoothDetailsMacAddressController.class).getPreferenceKey()); .add(use(BluetoothDetailsButtonsController.class).getPreferenceKey());
if (!BluetoothUtils.isHeadset(mCachedDevice.getDevice())) {
visibleKeys.add(use(BluetoothDetailsMacAddressController.class).getPreferenceKey());
}
return visibleKeys.build();
} }
return null; return null;
} }

View File

@@ -296,6 +296,10 @@ public final class BluetoothDevicePreference extends GearPreference {
void onPreferenceAttributesChanged() { void onPreferenceAttributesChanged() {
try { try {
ThreadUtils.postOnBackgroundThread(() -> { ThreadUtils.postOnBackgroundThread(() -> {
if (mCachedDevice.getDevice() != null) {
Log.d(TAG, "onPreferenceAttributesChanged, start updating for device "
+ mCachedDevice.getDevice().getAnonymizedAddress());
}
@Nullable String name = mCachedDevice.getName(); @Nullable String name = mCachedDevice.getName();
// Null check is done at the framework // Null check is done at the framework
@Nullable String connectionSummary = getConnectionSummary(); @Nullable String connectionSummary = getConnectionSummary();
@@ -325,6 +329,7 @@ public final class BluetoothDevicePreference extends GearPreference {
notifyHierarchyChanged(); notifyHierarchyChanged();
} }
}); });
Log.d(TAG, "onPreferenceAttributesChanged, complete updating for device " + name);
}); });
} catch (RejectedExecutionException e) { } catch (RejectedExecutionException e) {
Log.w(TAG, "Handler thread unavailable, skipping getConnectionSummary!"); Log.w(TAG, "Handler thread unavailable, skipping getConnectionSummary!");

View File

@@ -335,6 +335,7 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
var unused = var unused =
ThreadUtils.postOnBackgroundThread( ThreadUtils.postOnBackgroundThread(
() -> { () -> {
Log.d(TAG, "updateTitle, check current status");
int titleResId; int titleResId;
if (isAudioModeOngoingCall(mContext)) { if (isAudioModeOngoingCall(mContext)) {
// in phone call // in phone call
@@ -347,6 +348,7 @@ public class AvailableMediaDeviceGroupController extends BasePreferenceControlle
// without phone call, not audio sharing // without phone call, not audio sharing
titleResId = R.string.connected_device_media_device_title; titleResId = R.string.connected_device_media_device_title;
} }
Log.d(TAG, "updateTitle, title = " + titleResId);
mContext.getMainExecutor() mContext.getMainExecutor()
.execute( .execute(
() -> { () -> {

View File

@@ -17,6 +17,7 @@ package com.android.settings.connecteddevice;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
@@ -34,18 +35,25 @@ import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.slices.SlicePreferenceController; import com.android.settings.slices.SlicePreferenceController;
import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.BluetoothUtils;
import com.android.settingslib.bluetooth.HearingAidStatsLogUtils; import com.android.settingslib.bluetooth.HearingAidStatsLogUtils;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.search.SearchIndexable; import com.android.settingslib.search.SearchIndexable;
@SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC) @SearchIndexable(forTarget = SearchIndexable.ALL & ~SearchIndexable.ARC)
public class ConnectedDeviceDashboardFragment extends DashboardFragment { public class ConnectedDeviceDashboardFragment extends DashboardFragment {
private static final String TAG = "ConnectedDeviceFrag"; private static final String TAG = "ConnectedDeviceFrag";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); private static final String SETTINGS_SEARCH_ACTION =
private static final String SLICE_ACTION = "com.android.settings.SEARCH_RESULT_TRAMPOLINE"; "com.android.settings.SEARCH_RESULT_TRAMPOLINE";
@VisibleForTesting static final String KEY_CONNECTED_DEVICES = "connected_device_list"; @VisibleForTesting static final String KEY_CONNECTED_DEVICES = "connected_device_list";
@VisibleForTesting static final String KEY_AVAILABLE_DEVICES = "available_device_list"; @VisibleForTesting static final String KEY_AVAILABLE_DEVICES = "available_device_list";
private static final String ENTRYPOINT_SYSUI = "bt_settings_entrypoint_sysui";
private static final String ENTRYPOINT_SETTINGS = "bt_settings_entrypoint_settings_click";
private static final String ENTRYPOINT_SETTINGS_SEARCH =
"bt_settings_entrypoint_settings_search";
private static final String ENTRYPOINT_OTHER = "bt_settings_entrypoint_other";
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
return SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY; return SettingsEnums.SETTINGS_CONNECTED_DEVICE_CATEGORY;
@@ -71,15 +79,16 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
super.onAttach(context); super.onAttach(context);
String callingAppPackageName = String callingAppPackageName =
((SettingsActivity) getActivity()).getInitialCallingPackage(); ((SettingsActivity) getActivity()).getInitialCallingPackage();
String action = getIntent() != null ? getIntent().getAction() : ""; Intent intent = getIntent();
if (DEBUG) { String action = intent != null ? intent.getAction() : "";
Log.d(
TAG, Log.d(
"onAttach() calling package name is : " TAG,
+ callingAppPackageName "onAttach() calling package name is : "
+ ", action : " + callingAppPackageName
+ action); + ", action : "
} + action);
if (BluetoothUtils.isAudioSharingUIAvailable(context)) { if (BluetoothUtils.isAudioSharingUIAvailable(context)) {
use(AudioSharingDevicePreferenceController.class).init(this); use(AudioSharingDevicePreferenceController.class).init(this);
} }
@@ -100,16 +109,51 @@ public class ConnectedDeviceDashboardFragment extends DashboardFragment {
provider.sendActivityIfAvailable(category); provider.sendActivityIfAvailable(category);
} }
} }
logPageEntrypoint(context, callingAppPackageName, intent);
} }
@VisibleForTesting @VisibleForTesting
boolean isAlwaysDiscoverable(String callingAppPackageName, String action) { boolean isAlwaysDiscoverable(String callingAppPackageName, String action) {
return TextUtils.equals(SLICE_ACTION, action) return TextUtils.equals(SETTINGS_SEARCH_ACTION, action)
? false ? false
: TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName) : TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName)
|| TextUtils.equals(Utils.SYSTEMUI_PACKAGE_NAME, callingAppPackageName); || TextUtils.equals(Utils.SYSTEMUI_PACKAGE_NAME, callingAppPackageName);
} }
private void logPageEntrypoint(Context context, String callingAppPackageName, Intent intent) {
String action = intent != null ? intent.getAction() : "";
if (TextUtils.equals(Utils.SYSTEMUI_PACKAGE_NAME, callingAppPackageName)) {
mMetricsFeatureProvider.action(
context, SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT, ENTRYPOINT_SYSUI);
} else if (TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName)
&& TextUtils.equals(Intent.ACTION_MAIN, action)) {
String sourceCategory =
intent != null
? Integer.toString(
getIntent()
.getIntExtra(
MetricsFeatureProvider
.EXTRA_SOURCE_METRICS_CATEGORY,
SettingsEnums.PAGE_UNKNOWN))
: "";
mMetricsFeatureProvider.action(
context,
SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT,
ENTRYPOINT_SETTINGS + "_" + sourceCategory);
} else if (TextUtils.equals(Utils.SETTINGS_PACKAGE_NAME, callingAppPackageName)
&& TextUtils.equals(SETTINGS_SEARCH_ACTION, action)) {
mMetricsFeatureProvider.action(
context,
SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT,
ENTRYPOINT_SETTINGS_SEARCH);
} else {
mMetricsFeatureProvider.action(
context, SettingsEnums.SETTINGS_CONNECTED_DEVICES_ENTRYPOINT, ENTRYPOINT_OTHER);
}
}
/** For Search. */ /** For Search. */
public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider(R.xml.connected_devices); new BaseSearchIndexProvider(R.xml.connected_devices);

View File

@@ -18,6 +18,14 @@ package com.android.settings.localepicker;
import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT; import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT;
import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_CALLING_PAGE;
import static com.android.settings.regionalpreferences.RegionDialogFragment.CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION;
import static com.android.settings.regionalpreferences.RegionDialogFragment.DIALOG_CHANGE_SYSTEM_LOCALE_REGION;
import static com.android.settings.regionalpreferences.RegionDialogFragment.DIALOG_CHANGE_PREFERRED_LOCALE_REGION;
import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_DIALOG_TYPE;
import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_TARGET_LOCALE;
import static com.android.settings.regionalpreferences.RegionDialogFragment.ARG_REPLACED_TARGET_LOCALE;
import android.app.FragmentTransaction; import android.app.FragmentTransaction;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
@@ -50,11 +58,6 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity
private static final String TAG = LocalePickerWithRegionActivity.class.getSimpleName(); private static final String TAG = LocalePickerWithRegionActivity.class.getSimpleName();
private static final String PARENT_FRAGMENT_NAME = "localeListEditor"; private static final String PARENT_FRAGMENT_NAME = "localeListEditor";
private static final String CHILD_FRAGMENT_NAME = "LocalePickerWithRegion"; private static final String CHILD_FRAGMENT_NAME = "LocalePickerWithRegion";
private static final int DIALOG_CHANGE_SYSTEM_LOCALE_REGION = 1;
private static final int DIALOG_CHANGE_PREFERRED_LOCALE_REGION = 2;
private static final String ARG_DIALOG_TYPE = "arg_dialog_type";
private static final String ARG_TARGET_LOCALE = "arg_target_locale";
private static final String ARG_REPLACED_TARGET_LOCALE = "arg_replaced_target_locale";
private static final String TAG_DIALOG_CHANGE_REGION = "dialog_change_region"; private static final String TAG_DIALOG_CHANGE_REGION = "dialog_change_region";
private static final int DISPOSE = -1; private static final int DISPOSE = -1;
private static final int SHOW_DIALOG_FOR_SYSTEM_LANGUAGE = 0; private static final int SHOW_DIALOG_FOR_SYSTEM_LANGUAGE = 0;
@@ -139,6 +142,7 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity
LocaleStore.LocaleInfo locale, FragmentManager fragmentManager) { LocaleStore.LocaleInfo locale, FragmentManager fragmentManager) {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putInt(ARG_DIALOG_TYPE, DIALOG_CHANGE_SYSTEM_LOCALE_REGION); args.putInt(ARG_DIALOG_TYPE, DIALOG_CHANGE_SYSTEM_LOCALE_REGION);
args.putInt(ARG_CALLING_PAGE, CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION);
args.putSerializable(ARG_TARGET_LOCALE, locale); args.putSerializable(ARG_TARGET_LOCALE, locale);
RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance(); RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance();
regionDialogFragment.setArguments(args); regionDialogFragment.setArguments(args);
@@ -149,6 +153,7 @@ public class LocalePickerWithRegionActivity extends SettingsBaseActivity
LocaleStore.LocaleInfo locale, Locale replacedLocale, FragmentManager fragmentManager) { LocaleStore.LocaleInfo locale, Locale replacedLocale, FragmentManager fragmentManager) {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putInt(ARG_DIALOG_TYPE, DIALOG_CHANGE_PREFERRED_LOCALE_REGION); args.putInt(ARG_DIALOG_TYPE, DIALOG_CHANGE_PREFERRED_LOCALE_REGION);
args.putInt(ARG_CALLING_PAGE, CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION);
args.putSerializable(ARG_TARGET_LOCALE, locale); args.putSerializable(ARG_TARGET_LOCALE, locale);
args.putSerializable(ARG_REPLACED_TARGET_LOCALE, replacedLocale); args.putSerializable(ARG_REPLACED_TARGET_LOCALE, replacedLocale);
RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance(); RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance();

View File

@@ -16,11 +16,11 @@
package com.android.settings.network package com.android.settings.network
import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_CONNECTIVITY import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_MOBILE_NETWORK
import android.content.Context import android.content.Context
import android.provider.Settings.Secure.ADAPTIVE_CONNECTIVITY_MOBILE_NETWORK_ENABLED import android.provider.Settings.Secure.ADAPTIVE_CONNECTIVITY_MOBILE_NETWORK_ENABLED
import com.android.settings.R import com.android.settings.R
import com.android.settings.contract.KEY_ADAPTIVE_CONNECTIVITY import com.android.settings.contract.KEY_ADAPTIVE_MOBILE_NETWORK
import com.android.settings.metrics.PreferenceActionMetricsProvider import com.android.settings.metrics.PreferenceActionMetricsProvider
import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyValueStoreDelegate import com.android.settingslib.datastore.KeyValueStoreDelegate
@@ -38,12 +38,12 @@ class AdaptiveMobileNetworkTogglePreference() :
PreferenceActionMetricsProvider { PreferenceActionMetricsProvider {
override val preferenceActionMetrics: Int override val preferenceActionMetrics: Int
get() = ACTION_ADAPTIVE_CONNECTIVITY get() = ACTION_ADAPTIVE_MOBILE_NETWORK
override val key: String override val key: String
get() = KEY get() = KEY
override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_CONNECTIVITY) override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_MOBILE_NETWORK)
override fun storage(context: Context): KeyValueStore = override fun storage(context: Context): KeyValueStore =
AdaptiveMobileNetworkToggleStorage(context) AdaptiveMobileNetworkToggleStorage(context)

View File

@@ -25,6 +25,7 @@ import androidx.preference.Preference.OnPreferenceClickListener
import com.android.settings.R import com.android.settings.R
import com.android.settings.flags.Flags import com.android.settings.flags.Flags
import com.android.settings.network.AirplaneModePreference.Companion.isAirplaneModeOn import com.android.settings.network.AirplaneModePreference.Companion.isAirplaneModeOn
import com.android.settings.network.SatelliteRepository.Companion.isSatelliteOn
import com.android.settings.network.SubscriptionUtil.getUniqueSubscriptionDisplayName import com.android.settings.network.SubscriptionUtil.getUniqueSubscriptionDisplayName
import com.android.settings.network.telephony.SimRepository import com.android.settings.network.telephony.SimRepository
import com.android.settings.network.telephony.SubscriptionRepository import com.android.settings.network.telephony.SubscriptionRepository
@@ -32,6 +33,7 @@ import com.android.settings.network.telephony.euicc.EuiccRepository
import com.android.settings.restriction.PreferenceRestrictionMixin import com.android.settings.restriction.PreferenceRestrictionMixin
import com.android.settings.spa.network.getAddSimIntent import com.android.settings.spa.network.getAddSimIntent
import com.android.settings.spa.network.startAddSimFlow import com.android.settings.spa.network.startAddSimFlow
import com.android.settings.spa.network.startSatelliteWarningDialogFlow
import com.android.settingslib.RestrictedPreference import com.android.settingslib.RestrictedPreference
import com.android.settingslib.datastore.HandlerExecutor import com.android.settingslib.datastore.HandlerExecutor
import com.android.settingslib.datastore.KeyedObserver import com.android.settingslib.datastore.KeyedObserver
@@ -120,7 +122,11 @@ class MobileNetworkListScreen :
val summary = preference.summary ?: return true // no-op val summary = preference.summary ?: return true // no-op
val context = preference.context val context = preference.context
if (summary == context.getString(R.string.mobile_network_summary_add_a_network)) { if (summary == context.getString(R.string.mobile_network_summary_add_a_network)) {
startAddSimFlow(context) // start intent if (isSatelliteOn(context, 3000)) {
startSatelliteWarningDialogFlow(context) // start intent
} else {
startAddSimFlow(context) // start intent
}
return true return true
} }
return false // start fragment return false // start fragment

View File

@@ -27,6 +27,7 @@ import com.android.settings.dashboard.DashboardFragment
import com.android.settings.network.telephony.SimRepository import com.android.settings.network.telephony.SimRepository
import com.android.settings.overlay.FeatureFactory.Companion.featureFactory import com.android.settings.overlay.FeatureFactory.Companion.featureFactory
import com.android.settings.spa.network.startAddSimFlow import com.android.settings.spa.network.startAddSimFlow
import com.android.settings.spa.network.startSatelliteWarningDialogFlow
import com.android.settingslib.RestrictedPreference import com.android.settingslib.RestrictedPreference
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow import com.android.settingslib.spaprivileged.settingsprovider.settingsGlobalBooleanFlow
@@ -51,11 +52,13 @@ constructor(
MobileNetworkSummaryRepository(context), MobileNetworkSummaryRepository(context),
private val airplaneModeOnFlow: Flow<Boolean> = private val airplaneModeOnFlow: Flow<Boolean> =
context.settingsGlobalBooleanFlow(Settings.Global.AIRPLANE_MODE_ON), context.settingsGlobalBooleanFlow(Settings.Global.AIRPLANE_MODE_ON),
private val satelliteIsStartedFlow: Flow<Boolean> = SatelliteRepository(context).getIsSessionStartedFlow()
) : BasePreferenceController(context, preferenceKey) { ) : BasePreferenceController(context, preferenceKey) {
private val metricsFeatureProvider = featureFactory.metricsFeatureProvider private val metricsFeatureProvider = featureFactory.metricsFeatureProvider
private var preference: RestrictedPreference? = null private var preference: RestrictedPreference? = null
private var isAirplaneModeOn = false private var isAirplaneModeOn = false
private var isSatelliteOn = false
override fun getAvailabilityStatus() = override fun getAvailabilityStatus() =
if (SimRepository(mContext).showMobileNetworkPageEntrance()) AVAILABLE if (SimRepository(mContext).showMobileNetworkPageEntrance()) AVAILABLE
@@ -74,6 +77,9 @@ constructor(
isAirplaneModeOn = it isAirplaneModeOn = it
updateEnabled() updateEnabled()
} }
satelliteIsStartedFlow.collectLatestWithLifecycle(viewLifecycleOwner) {
isSatelliteOn = it
}
} }
private fun update(state: MobileNetworkSummaryRepository.SubscriptionsState) { private fun update(state: MobileNetworkSummaryRepository.SubscriptionsState) {
@@ -87,7 +93,10 @@ constructor(
preference.onPreferenceClickListener = preference.onPreferenceClickListener =
Preference.OnPreferenceClickListener { Preference.OnPreferenceClickListener {
logPreferenceClick() logPreferenceClick()
startAddSimFlow(context) if (isSatelliteOn)
startSatelliteWarningDialogFlow(context)
else
startAddSimFlow(context)
true true
} }
} }

View File

@@ -32,11 +32,20 @@ import com.android.settingslib.wifi.WifiUtils
/** A dialog to show the warning message when device is under satellite mode. */ /** A dialog to show the warning message when device is under satellite mode. */
class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() { class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() {
private var warningType = TYPE_IS_UNKNOWN private var warningType = TYPE_IS_UNKNOWN
private var customizedContent: HashMap<Int, String> = HashMap<Int, String>()
private var isCustomizedContent = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
warningType = intent.getIntExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, TYPE_IS_UNKNOWN) isCustomizedContent = intent.hasExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT)
if (warningType == TYPE_IS_UNKNOWN) { if (isCustomizedContent) {
finish() customizedContent =
intent.getSerializableExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT)
as HashMap<Int, String>
} else {
warningType =
intent.getIntExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, TYPE_IS_UNKNOWN)
if (warningType == TYPE_IS_UNKNOWN) {
finish()
}
} }
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
} }
@@ -48,23 +57,52 @@ class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() {
) )
} }
fun getBodyString(): String {
if (isCustomizedContent) {
// For customized content
return customizedContent.get(CUSTOM_CONTENT_DESCRIPTION).toString()
} else {
// For wifi, bluetooth, airplane mode
return String.format(
getString(R.string.satellite_warning_dialog_content),
getTypeString(warningType)
)
}
}
fun getButtonString(): String {
if (isCustomizedContent)
// For customized content
return customizedContent.get(CUSTOM_CONTENT_BUTTON_NAME).toString()
else
// For wifi, bluetooth, airplane mode
return getString(com.android.settingslib.R.string.okay)
}
fun getTitleString(): String {
if (isCustomizedContent)
// For customized content
return customizedContent.get(CUSTOM_CONTENT_TITLE).toString()
else
// For wifi, bluetooth, airplane mode
return String.format(
getString(R.string.satellite_warning_dialog_title),
getTypeString(warningType)
)
}
@Composable @Composable
override fun Content() { override fun Content() {
SettingsAlertDialogContent( SettingsAlertDialogContent(
dismissButton = null, dismissButton = null,
confirmButton = AlertDialogButton( confirmButton = AlertDialogButton(
getString(com.android.settingslib.R.string.okay) getButtonString()
) { finish() }, ) { finish() },
title = String.format( title = getTitleString(),
getString(R.string.satellite_warning_dialog_title),
getTypeString(warningType)
),
text = { text = {
Text( Text(
String.format( getBodyString(),
getString(R.string.satellite_warning_dialog_content),
getTypeString(warningType)
),
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
textAlign = TextAlign.Center textAlign = TextAlign.Center
) )
@@ -83,9 +121,14 @@ class SatelliteWarningDialogActivity : SpaDialogWindowTypeActivity() {
companion object { companion object {
const val EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG: String = const val EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG: String =
"extra_type_of_satellite_warning_dialog" "extra_type_of_satellite_warning_dialog"
const val EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT: String =
"extra_type_of_satellite_customized_content"
const val TYPE_IS_UNKNOWN = -1 const val TYPE_IS_UNKNOWN = -1
const val TYPE_IS_WIFI = 0 const val TYPE_IS_WIFI = 0
const val TYPE_IS_BLUETOOTH = 1 const val TYPE_IS_BLUETOOTH = 1
const val TYPE_IS_AIRPLANE_MODE = 2 const val TYPE_IS_AIRPLANE_MODE = 2
const val CUSTOM_CONTENT_TITLE = 0
const val CUSTOM_CONTENT_DESCRIPTION = 1
const val CUSTOM_CONTENT_BUTTON_NAME = 2
} }
} }

View File

@@ -17,13 +17,13 @@
package com.android.settings.network package com.android.settings.network
import android.Manifest import android.Manifest
import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_CONNECTIVITY import android.app.settings.SettingsEnums.ACTION_ADAPTIVE_WIFI_SCORER
import android.content.Context import android.content.Context
import android.net.wifi.WifiManager import android.net.wifi.WifiManager
import android.provider.Settings.Secure.ADAPTIVE_CONNECTIVITY_WIFI_ENABLED import android.provider.Settings.Secure.ADAPTIVE_CONNECTIVITY_WIFI_ENABLED
import androidx.annotation.RequiresPermission import androidx.annotation.RequiresPermission
import com.android.settings.R import com.android.settings.R
import com.android.settings.contract.KEY_ADAPTIVE_CONNECTIVITY import com.android.settings.contract.KEY_ADAPTIVE_WIFI_SCORER
import com.android.settings.metrics.PreferenceActionMetricsProvider import com.android.settings.metrics.PreferenceActionMetricsProvider
import com.android.settingslib.datastore.KeyValueStore import com.android.settingslib.datastore.KeyValueStore
import com.android.settingslib.datastore.KeyValueStoreDelegate import com.android.settingslib.datastore.KeyValueStoreDelegate
@@ -42,12 +42,12 @@ class WifiScorerTogglePreference() :
PreferenceActionMetricsProvider { PreferenceActionMetricsProvider {
override val preferenceActionMetrics: Int override val preferenceActionMetrics: Int
get() = ACTION_ADAPTIVE_CONNECTIVITY get() = ACTION_ADAPTIVE_WIFI_SCORER
override val key: String override val key: String
get() = KEY get() = KEY
override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_CONNECTIVITY) override fun tags(context: Context) = arrayOf(KEY_ADAPTIVE_WIFI_SCORER)
override fun storage(context: Context): KeyValueStore = override fun storage(context: Context): KeyValueStore =
WifiScorerToggleStorage(context) WifiScorerToggleStorage(context)

View File

@@ -101,6 +101,10 @@ public class SatelliteSettingAccountInfoController extends TelephonyBasePreferen
@Override @Override
public int getAvailabilityStatus(int subId) { public int getAvailabilityStatus(int subId) {
if (mConfigBundle.getInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT)
== CARRIER_ROAMING_NTN_CONNECT_MANUAL) {
return AVAILABLE;
}
return mConfigBundle.getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL) return mConfigBundle.getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL)
? AVAILABLE ? AVAILABLE
: CONDITIONALLY_UNAVAILABLE; : CONDITIONALLY_UNAVAILABLE;

View File

@@ -0,0 +1,66 @@
/*
* 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.privatespace;
import static com.android.settingslib.widget.preference.illustration.R.string.settingslib_action_label_pause;
import static com.android.settingslib.widget.preference.illustration.R.string.settingslib_action_label_resume;
import static com.android.settingslib.widget.preference.illustration.R.string.settingslib_illustration_content_description;
import android.content.Context;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import androidx.core.view.AccessibilityDelegateCompat;
import androidx.core.view.ViewCompat;
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import com.airbnb.lottie.LottieAnimationView;
public class PrivateSpaceAccessibilityUtils {
static void updateAccessibilityActionForAnimation(Context context,
LottieAnimationView animationView, boolean isAnimationPlaying) {
animationView.setContentDescription(
context.getString(settingslib_illustration_content_description));
ViewCompat.setAccessibilityDelegate(animationView, new AccessibilityDelegateCompat() {
@Override
public void onInitializeAccessibilityNodeInfo(
View host, AccessibilityNodeInfoCompat info) {
super.onInitializeAccessibilityNodeInfo(host, info);
// Clearing the class name to ensure the animation is not called out as "button"
// inside the TalkBack flows
info.setClassName("");
info.removeAction(
AccessibilityNodeInfoCompat.AccessibilityActionCompat.ACTION_CLICK);
final AccessibilityNodeInfoCompat.AccessibilityActionCompat clickAction =
new AccessibilityNodeInfoCompat.AccessibilityActionCompat(
AccessibilityNodeInfo.ACTION_CLICK,
getActionLabelForAnimation(context, isAnimationPlaying));
info.addAction(clickAction);
}
});
}
private static String getActionLabelForAnimation(Context context, boolean isAnimationPlaying) {
if (isAnimationPlaying) {
return context.getString(settingslib_action_label_pause);
} else {
return context.getString(settingslib_action_label_resume);
}
}
}

View File

@@ -76,6 +76,8 @@ public class PrivateSpaceEducation extends InstrumentedFragment {
LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation); LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView); LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView)); lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(),
lottieAnimationView, mIsAnimationPlaying);
TextView infoTextView = rootView.findViewById(R.id.learn_more); TextView infoTextView = rootView.findViewById(R.id.learn_more);
Pattern pattern = Pattern.compile(infoTextView.getText().toString()); Pattern pattern = Pattern.compile(infoTextView.getText().toString());
@@ -121,5 +123,7 @@ public class PrivateSpaceEducation extends InstrumentedFragment {
lottieAnimationView.playAnimation(); lottieAnimationView.playAnimation();
} }
mIsAnimationPlaying = !mIsAnimationPlaying; mIsAnimationPlaying = !mIsAnimationPlaying;
PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(),
lottieAnimationView, mIsAnimationPlaying);
} }
} }

View File

@@ -94,6 +94,8 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment {
LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation); LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView); LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView)); lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(),
lottieAnimationView, mIsAnimationPlaying);
return rootView; return rootView;
} }
@@ -141,5 +143,7 @@ public class PrivateSpaceSetLockFragment extends InstrumentedFragment {
lottieAnimationView.playAnimation(); lottieAnimationView.playAnimation();
} }
mIsAnimationPlaying = !mIsAnimationPlaying; mIsAnimationPlaying = !mIsAnimationPlaying;
PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(),
lottieAnimationView, mIsAnimationPlaying);
} }
} }

View File

@@ -83,6 +83,8 @@ public class SetupSuccessFragment extends InstrumentedFragment {
LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation); LottieAnimationView lottieAnimationView = rootView.findViewById(R.id.lottie_animation);
LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView); LottieColorUtils.applyDynamicColors(getContext(), lottieAnimationView);
lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView)); lottieAnimationView.setOnClickListener(v -> handleAnimationClick(lottieAnimationView));
PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(),
lottieAnimationView, mIsAnimationPlaying);
return rootView; return rootView;
} }
@@ -152,5 +154,7 @@ public class SetupSuccessFragment extends InstrumentedFragment {
lottieAnimationView.playAnimation(); lottieAnimationView.playAnimation();
} }
mIsAnimationPlaying = !mIsAnimationPlaying; mIsAnimationPlaying = !mIsAnimationPlaying;
PrivateSpaceAccessibilityUtils.updateAccessibilityActionForAnimation(getContext(),
lottieAnimationView, mIsAnimationPlaying);
} }
} }

View File

@@ -16,8 +16,13 @@
package com.android.settings.regionalpreferences; package com.android.settings.regionalpreferences;
import static android.app.settings.SettingsEnums.ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_POSITIVE_BTN_CLICKED;
import static android.app.settings.SettingsEnums.ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_NEGATIVE_BTN_CLICKED;
import static android.app.settings.SettingsEnums.ACTION_CHANGE_REGION_DIALOG_NEGATIVE_BTN_CLICKED;
import static android.app.settings.SettingsEnums.ACTION_CHANGE_REGION_DIALOG_POSITIVE_BTN_CLICKED;
import static android.app.settings.SettingsEnums.CHANGE_REGION_DIALOG;
import android.app.Dialog; import android.app.Dialog;
import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
@@ -46,12 +51,17 @@ import java.util.Set;
* Create a dialog for system region events. * Create a dialog for system region events.
*/ */
public class RegionDialogFragment extends InstrumentedDialogFragment { public class RegionDialogFragment extends InstrumentedDialogFragment {
public static final String ARG_CALLING_PAGE = "arg_calling_page";
public static final int CALLING_PAGE_LANGUAGE_CHOOSE_A_REGION = 0;
public static final int CALLING_PAGE_REGIONAL_PREFERENCES_REGION_PICKER = 1;
public static final int DIALOG_CHANGE_SYSTEM_LOCALE_REGION = 1;
public static final int DIALOG_CHANGE_PREFERRED_LOCALE_REGION = 2;
public static final String ARG_DIALOG_TYPE = "arg_dialog_type";
public static final String ARG_TARGET_LOCALE = "arg_target_locale";
public static final String ARG_REPLACED_TARGET_LOCALE = "arg_replaced_target_locale";
private static final String TAG = "RegionDialogFragment"; private static final String TAG = "RegionDialogFragment";
static final int DIALOG_CHANGE_SYSTEM_LOCALE_REGION = 1;
static final int DIALOG_CHANGE_PREFERRED_LOCALE_REGION = 2;
static final String ARG_DIALOG_TYPE = "arg_dialog_type";
static final String ARG_TARGET_LOCALE = "arg_target_locale";
static final String ARG_REPLACED_TARGET_LOCALE = "arg_replaced_target_locale";
/** /**
* Use this factory method to create a new instance of * Use this factory method to create a new instance of
@@ -66,7 +76,7 @@ public class RegionDialogFragment extends InstrumentedDialogFragment {
@Override @Override
public int getMetricsCategory() { public int getMetricsCategory() {
return SettingsEnums.CHANGE_REGION_DIALOG; return CHANGE_REGION_DIALOG;
} }
@NonNull @NonNull
@@ -114,6 +124,7 @@ public class RegionDialogFragment extends InstrumentedDialogFragment {
class RegionDialogController implements DialogInterface.OnClickListener { class RegionDialogController implements DialogInterface.OnClickListener {
private final Context mContext; private final Context mContext;
private final int mDialogType; private final int mDialogType;
private final int mCallingPage;
private final LocaleStore.LocaleInfo mLocaleInfo; private final LocaleStore.LocaleInfo mLocaleInfo;
private final Locale mReplacedLocale; private final Locale mReplacedLocale;
private final MetricsFeatureProvider mMetricsFeatureProvider; private final MetricsFeatureProvider mMetricsFeatureProvider;
@@ -123,6 +134,7 @@ public class RegionDialogFragment extends InstrumentedDialogFragment {
mContext = context; mContext = context;
Bundle arguments = dialogFragment.getArguments(); Bundle arguments = dialogFragment.getArguments();
mDialogType = arguments.getInt(ARG_DIALOG_TYPE); mDialogType = arguments.getInt(ARG_DIALOG_TYPE);
mCallingPage = arguments.getInt(ARG_CALLING_PAGE);
mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE); mLocaleInfo = (LocaleStore.LocaleInfo) arguments.getSerializable(ARG_TARGET_LOCALE);
mReplacedLocale = (Locale) arguments.getSerializable(ARG_REPLACED_TARGET_LOCALE); mReplacedLocale = (Locale) arguments.getSerializable(ARG_REPLACED_TARGET_LOCALE);
mMetricsFeatureProvider = mMetricsFeatureProvider =
@@ -137,8 +149,10 @@ public class RegionDialogFragment extends InstrumentedDialogFragment {
updateRegion(mLocaleInfo.getLocale().toLanguageTag()); updateRegion(mLocaleInfo.getLocale().toLanguageTag());
mMetricsFeatureProvider.action( mMetricsFeatureProvider.action(
mContext, mContext,
SettingsEnums.ACTION_CHANGE_REGION_DIALOG_POSITIVE_BTN_CLICKED); mDialogType == DIALOG_CHANGE_SYSTEM_LOCALE_REGION
// TODO: add new metrics for DIALOG_CHANGE_PREFERRED_LOCALE_REGION ? ACTION_CHANGE_REGION_DIALOG_POSITIVE_BTN_CLICKED
: ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_POSITIVE_BTN_CLICKED,
mCallingPage);
dismiss(); dismiss();
if (getActivity() != null) { if (getActivity() != null) {
getActivity().finish(); getActivity().finish();
@@ -146,8 +160,10 @@ public class RegionDialogFragment extends InstrumentedDialogFragment {
} else { } else {
mMetricsFeatureProvider.action( mMetricsFeatureProvider.action(
mContext, mContext,
SettingsEnums.ACTION_CHANGE_REGION_DIALOG_NEGATIVE_BTN_CLICKED); mDialogType == DIALOG_CHANGE_SYSTEM_LOCALE_REGION
// TODO: add new metrics for DIALOG_CHANGE_PREFERRED_LOCALE_REGION ? ACTION_CHANGE_REGION_DIALOG_NEGATIVE_BTN_CLICKED
: ACTION_CHANGE_PREFERRED_LANGUAGE_REGION_NEGATIVE_BTN_CLICKED,
mCallingPage);
dismiss(); dismiss();
} }
} }

View File

@@ -167,8 +167,12 @@ public abstract class RegionPickerBaseListPreferenceController extends BasePrefe
mFragmentManager = mParent.getChildFragmentManager(); mFragmentManager = mParent.getChildFragmentManager();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putInt(RegionDialogFragment.ARG_DIALOG_TYPE, args.putInt(
RegionDialogFragment.ARG_DIALOG_TYPE,
RegionDialogFragment.DIALOG_CHANGE_SYSTEM_LOCALE_REGION); RegionDialogFragment.DIALOG_CHANGE_SYSTEM_LOCALE_REGION);
args.putInt(
RegionDialogFragment.ARG_CALLING_PAGE,
RegionDialogFragment.CALLING_PAGE_REGIONAL_PREFERENCES_REGION_PICKER);
args.putSerializable(RegionDialogFragment.ARG_TARGET_LOCALE, localeInfo); args.putSerializable(RegionDialogFragment.ARG_TARGET_LOCALE, localeInfo);
RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance(); RegionDialogFragment regionDialogFragment = RegionDialogFragment.newInstance();
regionDialogFragment.setArguments(args); regionDialogFragment.setArguments(args);

View File

@@ -35,6 +35,10 @@ 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.Utils import com.android.settings.Utils
import com.android.settings.network.SatelliteWarningDialogActivity
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_BUTTON_NAME
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_DESCRIPTION
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_TITLE
import com.android.settings.network.SubscriptionUtil import com.android.settings.network.SubscriptionUtil
import com.android.settings.network.telephony.MobileNetworkUtils import com.android.settings.network.telephony.MobileNetworkUtils
import com.android.settings.network.telephony.SubscriptionActivationRepository import com.android.settings.network.telephony.SubscriptionActivationRepository
@@ -143,3 +147,14 @@ fun getAddSimIntent() = Intent(EuiccManager.ACTION_PROVISION_EMBEDDED_SUBSCRIPTI
setPackage(Utils.PHONE_PACKAGE_NAME) setPackage(Utils.PHONE_PACKAGE_NAME)
putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true) putExtra(EuiccManager.EXTRA_FORCE_PROVISION, true)
} }
fun startSatelliteWarningDialogFlow(context: Context) = context.startActivity(getSatelliteWarningDialogIntent(context))
fun getSatelliteWarningDialogIntent(context: Context) = Intent(context,
SatelliteWarningDialogActivity::class.java).apply {
val content = HashMap<Int, String>()
content.put(CUSTOM_CONTENT_TITLE, context.getString(R.string.title_satellite_dialog_for_sim_restriction))
content.put(CUSTOM_CONTENT_DESCRIPTION, context.getString(R.string.description_satellite_dialog_for_sim_restriction))
content.put(CUSTOM_CONTENT_BUTTON_NAME, context.getString(R.string.okay))
putExtra(SatelliteWarningDialogActivity.EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT, content)
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (C) 2025 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.supervision
import android.app.KeyguardManager
import android.content.Context
import android.os.UserHandle
import android.os.UserManager
import android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING
import androidx.annotation.VisibleForTesting
/** Convenience methods for interacting with the supervising user profile. */
open class SupervisionHelper private constructor(context: Context) {
private val mUserManager = context.getSystemService(UserManager::class.java)
private val mKeyguardManager = context.getSystemService(KeyguardManager::class.java)
fun getSupervisingUserHandle(): UserHandle? {
for (user in (mUserManager?.users ?: emptyList())) {
if (user.userType.equals(USER_TYPE_PROFILE_SUPERVISING)) {
return user.userHandle
}
}
return null
}
fun isSupervisingCredentialSet(): Boolean {
val supervisingUserId = getSupervisingUserHandle()?.identifier ?: return false
return mKeyguardManager?.isDeviceSecure(supervisingUserId) ?: false
}
companion object {
@Volatile @VisibleForTesting var sInstance: SupervisionHelper? = null
fun getInstance(context: Context): SupervisionHelper {
return sInstance
?: synchronized(this) {
sInstance ?: SupervisionHelper(context).also { sInstance = it }
}
}
}
}

View File

@@ -83,6 +83,7 @@ class SupervisionMainSwitchPreference(context: Context) :
val newValue = !supervisionMainSwitchStorage.getBoolean(KEY)!! val newValue = !supervisionMainSwitchStorage.getBoolean(KEY)!!
mainSwitchPreference.setChecked(newValue) mainSwitchPreference.setChecked(newValue)
updateDependentPreferencesEnabledState(mainSwitchPreference, newValue) updateDependentPreferencesEnabledState(mainSwitchPreference, newValue)
context.notifyPreferenceChange(SupervisionPinManagementScreen.KEY)
} }
return true return true
@@ -110,10 +111,7 @@ class SupervisionMainSwitchPreference(context: Context) :
isChecked: Boolean, isChecked: Boolean,
) { ) {
preference?.parent?.forEachRecursively { preference?.parent?.forEachRecursively {
if ( if (it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1) {
it.parent?.key == SupervisionDashboardScreen.SUPERVISION_DYNAMIC_GROUP_1 ||
it.key == SupervisionPinManagementScreen.KEY
) {
it.isEnabled = isChecked it.isEnabled = isChecked
} }
} }

View File

@@ -17,16 +17,20 @@ package com.android.settings.supervision
import android.content.Context import android.content.Context
import com.android.settings.R import com.android.settings.R
import com.android.settingslib.metadata.PreferenceAvailabilityProvider
import com.android.settingslib.metadata.ProvidePreferenceScreen import com.android.settingslib.metadata.ProvidePreferenceScreen
import com.android.settingslib.metadata.preferenceHierarchy import com.android.settingslib.metadata.preferenceHierarchy
import com.android.settingslib.preference.PreferenceScreenCreator import com.android.settingslib.preference.PreferenceScreenCreator
/** Pin Management landing page (Settings > Supervision > Manage Pin). */ /** Pin Management landing page (Settings > Supervision > Manage Pin). */
@ProvidePreferenceScreen(SupervisionPinManagementScreen.KEY) @ProvidePreferenceScreen(SupervisionPinManagementScreen.KEY)
class SupervisionPinManagementScreen : PreferenceScreenCreator { class SupervisionPinManagementScreen : PreferenceScreenCreator, PreferenceAvailabilityProvider {
override val key: String override val key: String
get() = KEY get() = KEY
override fun isAvailable(context: Context) =
SupervisionHelper.getInstance(context).isSupervisingCredentialSet()
override val title: Int override val title: Int
get() = R.string.supervision_pin_management_preference_title get() = R.string.supervision_pin_management_preference_title
@@ -36,7 +40,7 @@ class SupervisionPinManagementScreen : PreferenceScreenCreator {
// TODO(b/391994031): dynamically update the icon according to PIN status. // TODO(b/391994031): dynamically update the icon according to PIN status.
override val icon: Int override val icon: Int
get() = R.drawable.ic_pin get() = R.drawable.ic_pin_outline
override fun fragmentClass() = SupervisionPinManagementFragment::class.java override fun fragmentClass() = SupervisionPinManagementFragment::class.java

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2025 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.accessibility;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.res.Resources;
import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider;
import com.android.settings.R;
import com.android.settingslib.widget.TopIntroPreference;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.robolectric.RobolectricTestRunner;
/**
* Tests for {@link HearingDevicePairingIntroPreferenceController}.
*/
@RunWith(RobolectricTestRunner.class)
public class HearingDevicePairingIntroPreferenceControllerTest {
@Rule
public final MockitoRule mockito = MockitoJUnit.rule();
@Spy
private final Context mContext = ApplicationProvider.getApplicationContext();
@Spy
private final Resources mResources = mContext.getResources();
@Mock
private PreferenceScreen mScreen;
@Mock
private HearingAidHelper mHelper;
private HearingDevicePairingIntroPreferenceController mController;
private TopIntroPreference mPreference;
@Before
public void setUp() {
mController = new HearingDevicePairingIntroPreferenceController(mContext, "test_key",
mHelper);
mPreference = new TopIntroPreference(mContext);
mPreference.setKey("test_key");
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference);
when(mContext.getResources()).thenReturn(mResources);
}
@Test
public void getAvailabilityStatus_hearingAidSupported_available() {
when(mHelper.isHearingAidSupported()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailabilityStatus_hearingAidNotSupported_unsupportedOnDevice() {
when(mHelper.isHearingAidSupported()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE);
}
@Test
public void displayPreference_ashaHapSupported_expectedTitle() {
when(mHelper.isAshaProfileSupported()).thenReturn(true);
when(mHelper.isHapClientProfileSupported()).thenReturn(true);
mController.displayPreference(mScreen);
assertThat(mPreference.getTitle().toString()).isEqualTo(
mContext.getString(R.string.accessibility_hearing_device_pairing_intro));
}
@Test
public void displayPreference_ashaSupported_expectedTitle() {
when(mHelper.isAshaProfileSupported()).thenReturn(true);
when(mHelper.isHapClientProfileSupported()).thenReturn(false);
mController.displayPreference(mScreen);
assertThat(mPreference.getTitle().toString()).isEqualTo(
mContext.getString(R.string.accessibility_hearing_device_pairing_asha_only_intro));
}
@Test
public void displayPreference_hapSupported_expectedTitle() {
when(mHelper.isAshaProfileSupported()).thenReturn(false);
when(mHelper.isHapClientProfileSupported()).thenReturn(true);
mController.displayPreference(mScreen);
assertThat(mPreference.getTitle().toString()).isEqualTo(
mContext.getString(R.string.accessibility_hearing_device_pairing_hap_only_intro));
}
}

View File

@@ -70,6 +70,7 @@ import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference; import androidx.preference.Preference;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.settings.biometrics.fingerprint.feature.FingerprintExtPreferencesProvider;
import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settings.password.ChooseLockSettingsHelper;
import com.android.settings.password.ConfirmDeviceCredentialActivity; import com.android.settings.password.ConfirmDeviceCredentialActivity;
import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.BaseSearchIndexProvider;
@@ -79,6 +80,7 @@ import com.android.settings.testutils.shadow.ShadowLockPatternUtils;
import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment; import com.android.settings.testutils.shadow.ShadowSettingsPreferenceFragment;
import com.android.settings.testutils.shadow.ShadowUserManager; import com.android.settings.testutils.shadow.ShadowUserManager;
import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settings.testutils.shadow.ShadowUtils;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.RestrictedSwitchPreference; import com.android.settingslib.RestrictedSwitchPreference;
import org.junit.After; import org.junit.After;
@@ -123,6 +125,12 @@ public class FingerprintSettingsFragmentTest {
private PackageManager mPackageManager; private PackageManager mPackageManager;
@Mock @Mock
private BiometricManager mBiometricManager; private BiometricManager mBiometricManager;
@Mock
private FingerprintExtPreferencesProvider mExtPreferencesProvider;
@Mock
private RestrictedPreference mRestrictedPreference0;
@Mock
private RestrictedPreference mRestrictedPreference1;
@Captor @Captor
private ArgumentCaptor<CancellationSignal> mCancellationSignalArgumentCaptor = private ArgumentCaptor<CancellationSignal> mCancellationSignalArgumentCaptor =
@@ -159,6 +167,11 @@ public class FingerprintSettingsFragmentTest {
when(mFakeFeatureFactory.getFingerprintFeatureProvider() when(mFakeFeatureFactory.getFingerprintFeatureProvider()
.getFingerprintSettingsFeatureProvider()) .getFingerprintSettingsFeatureProvider())
.thenReturn(mFingerprintSettingsFeatureProvider); .thenReturn(mFingerprintSettingsFeatureProvider);
when(mFakeFeatureFactory.getFingerprintFeatureProvider()
.getExtPreferenceProvider(mContext))
.thenReturn(mExtPreferencesProvider);
when(mExtPreferencesProvider.getSize()).thenReturn(0);
} }
@After @After
@@ -417,6 +430,33 @@ public class FingerprintSettingsFragmentTest {
assertThat(checkEnrolledPerf).isNull(); assertThat(checkEnrolledPerf).isNull();
} }
@Test
public void testHasExtPreferences() {
String key0 = "ExtKey0";
String key1 = "ExtKey1";
when(mRestrictedPreference0.getKey()).thenReturn(key0);
when(mRestrictedPreference1.getKey()).thenReturn(key1);
when(mExtPreferencesProvider.getSize()).thenReturn(2);
when(mExtPreferencesProvider.newPreference(eq(0),
any(FingerprintExtPreferencesProvider.PreferenceInflater.class)))
.thenReturn(mRestrictedPreference0);
when(mExtPreferencesProvider.newPreference(eq(1),
any(FingerprintExtPreferencesProvider.PreferenceInflater.class)))
.thenReturn(mRestrictedPreference1);
Fingerprint fingerprint = new Fingerprint("Test", 0, 0);
doReturn(List.of(fingerprint)).when(mFingerprintManager).getEnrolledFingerprints(anyInt());
setUpFragment(false, PRIMARY_USER_ID, TYPE_UDFPS_OPTICAL, 5);
shadowOf(Looper.getMainLooper()).idle();
Preference preference0 = mFragment.findPreference(key0);
assertThat(preference0).isEqualTo(mRestrictedPreference0);
Preference preference1 = mFragment.findPreference(key1);
assertThat(preference1).isEqualTo(mRestrictedPreference1);
}
private void setSensor(@FingerprintSensorProperties.SensorType int sensorType, private void setSensor(@FingerprintSensorProperties.SensorType int sensorType,
int maxFingerprints) { int maxFingerprints) {
final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>(); final ArrayList<FingerprintSensorPropertiesInternal> props = new ArrayList<>();

View File

@@ -65,7 +65,7 @@ class SupervisionDashboardScreenTest {
val mainSwitchPreference = val mainSwitchPreference =
fragment.findPreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)!! fragment.findPreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)!!
val childPreference = val childPreference =
fragment.findPreference<Preference>(SupervisionPinManagementScreen.KEY)!! fragment.findPreference<Preference>(SupervisionWebContentFiltersScreen.KEY)!!
assertThat(childPreference.isEnabled).isFalse() assertThat(childPreference.isEnabled).isFalse()
@@ -89,7 +89,7 @@ class SupervisionDashboardScreenTest {
val mainSwitchPreference = val mainSwitchPreference =
fragment.findPreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)!! fragment.findPreference<MainSwitchPreference>(SupervisionMainSwitchPreference.KEY)!!
val childPreference = val childPreference =
fragment.findPreference<Preference>(SupervisionPinManagementScreen.KEY)!! fragment.findPreference<Preference>(SupervisionWebContentFiltersScreen.KEY)!!
assertThat(childPreference.isEnabled).isFalse() assertThat(childPreference.isEnabled).isFalse()

View File

@@ -15,25 +15,73 @@
*/ */
package com.android.settings.supervision package com.android.settings.supervision
import android.app.KeyguardManager
import android.content.Context import android.content.Context
import android.content.ContextWrapper
import android.content.pm.UserInfo
import android.os.UserManager
import android.os.UserManager.USER_TYPE_PROFILE_SUPERVISING
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R import com.android.settings.R
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
class SupervisionPinManagementScreenTest { class SupervisionPinManagementScreenTest {
private val context: Context = ApplicationProvider.getApplicationContext() private val mockKeyguardManager = mock<KeyguardManager>()
private val mockUserManager = mock<UserManager>()
private val context: Context =
object : ContextWrapper(ApplicationProvider.getApplicationContext()) {
override fun getSystemService(name: String): Any? =
when (name) {
Context.KEYGUARD_SERVICE -> mockKeyguardManager
Context.USER_SERVICE -> mockUserManager
else -> super.getSystemService(name)
}
}
private val supervisionPinManagementScreen = SupervisionPinManagementScreen() private val supervisionPinManagementScreen = SupervisionPinManagementScreen()
@Before
fun setup() {
SupervisionHelper.sInstance = null
}
@Test @Test
fun key() { fun key() {
assertThat(supervisionPinManagementScreen.key).isEqualTo(SupervisionPinManagementScreen.KEY) assertThat(supervisionPinManagementScreen.key).isEqualTo(SupervisionPinManagementScreen.KEY)
} }
@Test
fun isAvailable() {
whenever(mockUserManager.users).thenReturn(listOf(SUPERVISING_USER_INFO))
whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true)
assertThat(supervisionPinManagementScreen.isAvailable(context)).isTrue()
}
@Test
fun isAvailable_noSupervisingUser_returnsFalse() {
whenever(mockUserManager.users).thenReturn(emptyList())
whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(true)
assertThat(supervisionPinManagementScreen.isAvailable(context)).isFalse()
}
@Test
fun isAvailable_noSupervisingCredential_returnsFalse() {
whenever(mockUserManager.users).thenReturn(listOf(SUPERVISING_USER_INFO))
whenever(mockKeyguardManager.isDeviceSecure(SUPERVISING_USER_ID)).thenReturn(false)
assertThat(supervisionPinManagementScreen.isAvailable(context)).isFalse()
}
@Test @Test
fun getTitle() { fun getTitle() {
assertThat(supervisionPinManagementScreen.title) assertThat(supervisionPinManagementScreen.title)
@@ -45,4 +93,16 @@ class SupervisionPinManagementScreenTest {
assertThat(supervisionPinManagementScreen.summary) assertThat(supervisionPinManagementScreen.summary)
.isEqualTo(R.string.supervision_pin_management_preference_summary_add) .isEqualTo(R.string.supervision_pin_management_preference_summary_add)
} }
private companion object {
const val SUPERVISING_USER_ID = 5
val SUPERVISING_USER_INFO =
UserInfo(
SUPERVISING_USER_ID,
/* name */ "supervising",
/* iconPath */ "",
/* flags */ 0,
USER_TYPE_PROFILE_SUPERVISING,
)
}
} }

View File

@@ -28,6 +28,10 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.R import com.android.settings.R
import com.android.settings.network.SatelliteWarningDialogActivity import com.android.settings.network.SatelliteWarningDialogActivity
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_BUTTON_NAME
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_DESCRIPTION
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.CUSTOM_CONTENT_TITLE
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG import com.android.settings.network.SatelliteWarningDialogActivity.Companion.EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_AIRPLANE_MODE import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_AIRPLANE_MODE
import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_BLUETOOTH import com.android.settings.network.SatelliteWarningDialogActivity.Companion.TYPE_IS_BLUETOOTH
@@ -74,6 +78,33 @@ class SatelliteWarningDialogActivityTest {
scenario.close() scenario.close()
} }
@Test
fun launchActivity_checkCustomizedContent_hasContentIntent() {
val scenario = launchCustomizedDialogActivity()
scenario.onActivity { activity ->
assert(activity.intent.hasExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT))
}
scenario.close()
}
@Test
fun testCustomizedDialogIsExisted() {
val scenario = launchCustomizedDialogActivity()
composeTestRule.onNodeWithText(
getSatelliteTestContent().get(CUSTOM_CONTENT_BUTTON_NAME).toString()
).assertIsDisplayed()
composeTestRule.onNodeWithText(
getSatelliteTestContent().get(CUSTOM_CONTENT_TITLE).toString()
).assertIsDisplayed()
composeTestRule.onNodeWithText(
getSatelliteTestContent().get(CUSTOM_CONTENT_DESCRIPTION).toString()
).assertIsDisplayed()
scenario.close()
}
@Test @Test
fun launchActivity_unknownType_destroyActivity() { fun launchActivity_unknownType_destroyActivity() {
val scenario = launchDialogActivity(TYPE_IS_UNKNOWN) val scenario = launchDialogActivity(TYPE_IS_UNKNOWN)
@@ -117,10 +148,31 @@ class SatelliteWarningDialogActivityTest {
scenario.close() scenario.close()
} }
private fun launchDialogActivity(type: Int): ActivityScenario<SatelliteWarningDialogActivity> = launch( private fun launchDialogActivity(type: Int): ActivityScenario<SatelliteWarningDialogActivity> =
Intent( launch(Intent(
context, context,
SatelliteWarningDialogActivity::class.java SatelliteWarningDialogActivity::class.java
).putExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, type) ).putExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, type)
) )
private fun launchCustomizedDialogActivity(): ActivityScenario<SatelliteWarningDialogActivity> =
launch(Intent(
context,
SatelliteWarningDialogActivity::class.java
).putExtra(EXTRA_TYPE_OF_SATELLITE_CUSTOMIZED_CONTENT, getSatelliteTestContent())
)
private fun getSatelliteTestContent(): HashMap<Int, String> {
val content = HashMap<Int, String>()
content.put(CUSTOM_CONTENT_TITLE, TEST_TITLE)
content.put(CUSTOM_CONTENT_DESCRIPTION, TEST_DESCRIPTION)
content.put(CUSTOM_CONTENT_BUTTON_NAME, TEST_BUTTON_NAME)
return content
}
companion object {
const val TEST_TITLE = "TEST_TITLE"
const val TEST_DESCRIPTION = "TEST_DESCRIPTION"
const val TEST_BUTTON_NAME = "TEST_BUTTON_NAME"
}
} }

View File

@@ -16,6 +16,9 @@
package com.android.settings.network.telephony.satellite; package com.android.settings.network.telephony.satellite;
import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC;
import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL;
import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT;
import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL; import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL;
import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.AVAILABLE;
@@ -81,6 +84,8 @@ public class SatelliteSettingAccountInfoControllerTest {
@Test @Test
public void getAvailabilityStatus_entitlementNotSupport_returnConditionalUnavailable() { public void getAvailabilityStatus_entitlementNotSupport_returnConditionalUnavailable() {
mPersistableBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT,
CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC);
when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null); when(mContext.getSystemService(SatelliteManager.class)).thenReturn(null);
mController.init(TEST_SUB_ID, mPersistableBundle, false, false); mController.init(TEST_SUB_ID, mPersistableBundle, false, false);
@@ -91,6 +96,8 @@ public class SatelliteSettingAccountInfoControllerTest {
@Test @Test
public void getAvailabilityStatus_entitlementIsSupported_returnConditionalUnavailable() { public void getAvailabilityStatus_entitlementIsSupported_returnConditionalUnavailable() {
mPersistableBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT,
CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC);
mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true); mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);
mController.init(TEST_SUB_ID, mPersistableBundle, false, false); mController.init(TEST_SUB_ID, mPersistableBundle, false, false);
@@ -99,6 +106,17 @@ public class SatelliteSettingAccountInfoControllerTest {
assertThat(result).isEqualTo(AVAILABLE); assertThat(result).isEqualTo(AVAILABLE);
} }
@Test
public void getAvailabilityStatus_connectionTypeISManual_returnAvailable() {
mPersistableBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT,
CARRIER_ROAMING_NTN_CONNECT_MANUAL);
mController.init(TEST_SUB_ID, mPersistableBundle, false, false);
int result = mController.getAvailabilityStatus(TEST_SUB_ID);
assertThat(result).isEqualTo(AVAILABLE);
}
@Test @Test
public void displayPreference_showCategoryTitle_correctOperatorName() { public void displayPreference_showCategoryTitle_correctOperatorName() {
mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true); mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true);

View File

@@ -40,6 +40,7 @@ import com.android.settings.testutils.ResourcesUtils;
import com.android.settingslib.widget.FooterPreference; import com.android.settingslib.widget.FooterPreference;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
@@ -115,6 +116,7 @@ public class SatelliteSettingFooterControllerTest {
} }
@Test @Test
@Ignore("b/405279842")
public void displayPreferenceScreen_emergencyMsgSupport_noEmergencyContent() { public void displayPreferenceScreen_emergencyMsgSupport_noEmergencyContent() {
mPersistableBundle.putBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true); mPersistableBundle.putBoolean(KEY_EMERGENCY_MESSAGING_SUPPORTED_BOOL, true);
PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext); PreferenceScreen screen = new PreferenceManager(mContext).createPreferenceScreen(mContext);