From c9569b1cbdf626cf6579de5fe830f4515f02f4be Mon Sep 17 00:00:00 2001 From: Kanyinsola Fapohunda Date: Wed, 19 Feb 2025 07:09:49 -0800 Subject: [PATCH 1/6] Change namespace for time_help_and_feedback_feature_supported server flag This change moves the time_help_and_feedback_feature_supported flag from the settings_ui namespace to the system_time namespace. Flag: EXEMPT refactor Bug: 283239837 Change-Id: Ic1fcafd3cdbd263d7b800ac7676701628361de63 --- src/com/android/settings/datetime/DateTimeLaunchUtils.java | 4 ++-- .../datetime/TimeFeedbackPreferenceControllerTest.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/com/android/settings/datetime/DateTimeLaunchUtils.java b/src/com/android/settings/datetime/DateTimeLaunchUtils.java index aef0ff2080b..f8cf0be2047 100644 --- a/src/com/android/settings/datetime/DateTimeLaunchUtils.java +++ b/src/com/android/settings/datetime/DateTimeLaunchUtils.java @@ -15,7 +15,7 @@ */ package com.android.settings.datetime; -import static android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI; +import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME; import android.provider.DeviceConfig; @@ -47,6 +47,6 @@ final class DateTimeLaunchUtils { private static boolean isFeedbackFeatureSupportedOnThisDevice() { boolean defaultIsSupported = false; return DeviceConfig.getBoolean( - NAMESPACE_SETTINGS_UI, KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, defaultIsSupported); + NAMESPACE_SYSTEM_TIME, KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, defaultIsSupported); } } diff --git a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java index 196aa36d8de..6cbb14f2142 100644 --- a/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/datetime/TimeFeedbackPreferenceControllerTest.java @@ -16,7 +16,7 @@ package com.android.settings.datetime; -import static android.provider.DeviceConfig.NAMESPACE_SETTINGS_UI; +import static android.provider.DeviceConfig.NAMESPACE_SYSTEM_TIME; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; @@ -93,7 +93,7 @@ public class TimeFeedbackPreferenceControllerTest { @Test @EnableFlags({Flags.FLAG_DATETIME_FEEDBACK}) public void validIntentUri_targetHandlerNotFound_returnsConditionallyUnavailable() { - DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, + DeviceConfig.setProperty(NAMESPACE_SYSTEM_TIME, DateTimeLaunchUtils.KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, "true", true); when(mMockPackageManager.resolveActivity(any(), anyInt())).thenReturn(null); @@ -107,7 +107,7 @@ public class TimeFeedbackPreferenceControllerTest { @Test @EnableFlags({Flags.FLAG_DATETIME_FEEDBACK}) public void validIntentUri_targetHandlerAvailable_returnsAvailable() { - DeviceConfig.setProperty(NAMESPACE_SETTINGS_UI, + DeviceConfig.setProperty(NAMESPACE_SYSTEM_TIME, DateTimeLaunchUtils.KEY_HELP_AND_FEEDBACK_FEATURE_SUPPORTED, "true", true); when(mMockPackageManager.resolveActivity(any(), anyInt())).thenReturn( createDummyResolveInfo()); From a9e67c03273692a8c8ba9407a64b2b23e3de28f6 Mon Sep 17 00:00:00 2001 From: Haijie Hong Date: Wed, 19 Feb 2025 13:19:21 +0800 Subject: [PATCH 2/6] Add Nearby share entrypoint in DevicePicker Bug: 381799866 Test: local build Flag: com.android.settings.flags.enable_nearby_share_entrypoint Change-Id: Ied79b9eebe7eaf669e45922787c5b01e504822d8 --- .../settings_bluetooth_declarations.aconfig | 10 ++ res/drawable/ic_bluetooth_share_info.xml | 25 ++++ res/layout/nearby_sharing_suggestion_card.xml | 93 +++++++++++++ res/values/strings.xml | 4 + res/xml/device_picker.xml | 11 +- .../bluetooth/DevicePickerFragment.java | 21 +++ .../NearbySharePreferenceController.kt | 96 +++++++++++++ .../NearbySharePreferenceControllerTest.kt | 130 ++++++++++++++++++ 8 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 res/drawable/ic_bluetooth_share_info.xml create mode 100644 res/layout/nearby_sharing_suggestion_card.xml create mode 100644 src/com/android/settings/bluetooth/NearbySharePreferenceController.kt create mode 100644 tests/robotests/src/com/android/settings/bluetooth/NearbySharePreferenceControllerTest.kt diff --git a/aconfig/settings_bluetooth_declarations.aconfig b/aconfig/settings_bluetooth_declarations.aconfig index 7aa989bb0d3..4d2528a71db 100644 --- a/aconfig/settings_bluetooth_declarations.aconfig +++ b/aconfig/settings_bluetooth_declarations.aconfig @@ -44,3 +44,13 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "enable_nearby_share_entrypoint" + namespace: "cross_device_experiences" + description: "Show Nearby Share entrypoint in Bluetooth Sharing page" + bug: "381799866" + metadata { + purpose: PURPOSE_BUGFIX + } +} diff --git a/res/drawable/ic_bluetooth_share_info.xml b/res/drawable/ic_bluetooth_share_info.xml new file mode 100644 index 00000000000..860c5536f0f --- /dev/null +++ b/res/drawable/ic_bluetooth_share_info.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/layout/nearby_sharing_suggestion_card.xml b/res/layout/nearby_sharing_suggestion_card.xml new file mode 100644 index 00000000000..6c9d310e439 --- /dev/null +++ b/res/layout/nearby_sharing_suggestion_card.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index ba0c998180b..9282be22982 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -203,6 +203,10 @@ Route sounds to your hearing device or phone speaker Related + + Try sharing with %s + + The fastest way to send files to nearby Android devices Ringtone and alarms diff --git a/res/xml/device_picker.xml b/res/xml/device_picker.xml index 6f8d267cd66..5e7667dc80e 100644 --- a/res/xml/device_picker.xml +++ b/res/xml/device_picker.xml @@ -15,12 +15,21 @@ --> + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:settings="http://schemas.android.com/apk/res-auto"> + + diff --git a/src/com/android/settings/bluetooth/DevicePickerFragment.java b/src/com/android/settings/bluetooth/DevicePickerFragment.java index 2e810620e7c..3e88c825449 100644 --- a/src/com/android/settings/bluetooth/DevicePickerFragment.java +++ b/src/com/android/settings/bluetooth/DevicePickerFragment.java @@ -32,9 +32,11 @@ import android.util.Log; import android.view.Menu; import android.view.MenuInflater; +import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; import com.android.settings.R; +import com.android.settings.flags.Flags; import com.android.settings.password.PasswordUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.core.AbstractPreferenceController; @@ -48,6 +50,8 @@ import java.util.List; public final class DevicePickerFragment extends DeviceListPreferenceFragment { private static final String KEY_BT_DEVICE_LIST = "bt_device_list"; private static final String TAG = "DevicePickerFragment"; + private static final String EXTRA_ORIGINAL_SEND_INTENT = + "android.bluetooth.extra.DEVICE_PICKER_ORIGINAL_SEND_INTENT"; @VisibleForTesting BluetoothProgressCategory mAvailableDevicesCategory; @@ -104,6 +108,23 @@ public final class DevicePickerFragment extends DeviceListPreferenceFragment { setHasOptionsMenu(true); } + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + if (Flags.enableNearbyShareEntrypoint()) { + initNearbySharingController(); + } + } + + private void initNearbySharingController() { + Intent sendIntent = + getIntent().getParcelableExtra(EXTRA_ORIGINAL_SEND_INTENT, Intent.class); + if (sendIntent == null) { + return; + } + use(NearbySharePreferenceController.class).init(sendIntent); + } + @Override public void onStart() { super.onStart(); diff --git a/src/com/android/settings/bluetooth/NearbySharePreferenceController.kt b/src/com/android/settings/bluetooth/NearbySharePreferenceController.kt new file mode 100644 index 00000000000..bf7092552db --- /dev/null +++ b/src/com/android/settings/bluetooth/NearbySharePreferenceController.kt @@ -0,0 +1,96 @@ +/* + * 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.bluetooth + +import android.app.settings.SettingsEnums +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.content.pm.PackageManager.NameNotFoundException +import android.provider.Settings +import android.text.TextUtils +import android.view.View +import android.widget.TextView +import androidx.preference.PreferenceScreen +import com.android.settings.R +import com.android.settings.core.BasePreferenceController +import com.android.settings.overlay.FeatureFactory +import com.android.settingslib.widget.LayoutPreference + +/** Preference controller for Nearby Share. */ +class NearbySharePreferenceController(private val context: Context, key: String) : + BasePreferenceController(context, key) { + private lateinit var intent: Intent + private var nearbyComponentName: ComponentName? = null + private var nearbyLabel: CharSequence? = null + + fun init(sendIntent: Intent) { + this.intent = sendIntent + val componentString = + Settings.Secure.getString( + context.getContentResolver(), + Settings.Secure.NEARBY_SHARING_COMPONENT, + ) + if (TextUtils.isEmpty(componentString)) { + return + } + nearbyComponentName = ComponentName.unflattenFromString(componentString)?.also { + intent.setComponent(it) + nearbyLabel = getNearbyLabel(it) + } + } + + override fun getAvailabilityStatus(): Int { + if (nearbyLabel == null) { + return CONDITIONALLY_UNAVAILABLE + } + return AVAILABLE + } + + override fun displayPreference(screen: PreferenceScreen) { + super.displayPreference(screen) + val preference: LayoutPreference = screen.findPreference(preferenceKey) ?: return + + preference.findViewById(R.id.nearby_sharing_suggestion_title).text = + context.getString(R.string.bluetooth_try_nearby_share_title, nearbyLabel) + FeatureFactory.featureFactory.metricsFeatureProvider.action( + SettingsEnums.PAGE_UNKNOWN, + SettingsEnums.ACTION_NEARBY_SHARE_ENTRYPOINT_SHOWN, + SettingsEnums.BLUETOOTH_DEVICE_PICKER, + "", + 0 + ) + preference.findViewById(R.id.card_container).setOnClickListener { + FeatureFactory.featureFactory.metricsFeatureProvider.clicked( + SettingsEnums.BLUETOOTH_DEVICE_PICKER, + preferenceKey + ) + context.startActivity(intent) + true + } + } + + private fun getNearbyLabel(componentName: ComponentName): CharSequence? = + try { + context.packageManager + .getActivityInfo(componentName, PackageManager.GET_META_DATA) + .loadLabel(context.packageManager) + } catch(_: NameNotFoundException) { + null + } +} diff --git a/tests/robotests/src/com/android/settings/bluetooth/NearbySharePreferenceControllerTest.kt b/tests/robotests/src/com/android/settings/bluetooth/NearbySharePreferenceControllerTest.kt new file mode 100644 index 00000000000..2055e886c4e --- /dev/null +++ b/tests/robotests/src/com/android/settings/bluetooth/NearbySharePreferenceControllerTest.kt @@ -0,0 +1,130 @@ +/* + * 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.bluetooth + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.pm.ActivityInfo +import android.content.pm.PackageManager +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import com.android.settings.R +import com.android.settingslib.widget.LayoutPreference +import com.google.common.truth.Truth.assertThat +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.mockito.kotlin.any +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.eq +import org.mockito.kotlin.spy +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class NearbySharePreferenceControllerTest : BluetoothDetailsControllerTestBase() { + @get:Rule val mockitoRule: MockitoRule = MockitoJUnit.rule() + + @Mock private lateinit var intent: Intent + @Mock private lateinit var packageManager: PackageManager + @Mock private lateinit var activityInfo: ActivityInfo + + private lateinit var context: Context + private lateinit var controller: NearbySharePreferenceController + + override fun setUp() { + super.setUp() + context = spy(mContext) + whenever(context.packageManager).thenReturn(packageManager) + whenever( + packageManager.getActivityInfo( + eq(ComponentName.unflattenFromString(COMPONENT_NAME)!!), + eq(PackageManager.GET_META_DATA), + ) + ) + .thenReturn(activityInfo) + + controller = NearbySharePreferenceController(context, PREF_KEY) + } + + @Test + fun noIntent_notAvailable() { + Settings.Secure.putString( + context.contentResolver, + Settings.Secure.NEARBY_SHARING_COMPONENT, + COMPONENT_NAME, + ) + whenever(activityInfo.loadLabel(any())).thenReturn("App") + + assertThat(controller.isAvailable).isFalse() + } + + @Test + fun noNearbyComponent_notAvailable() { + controller.init(intent) + + assertThat(controller.isAvailable).isFalse() + } + + @Test + fun hasIntentAndNearbyComponent_available() { + Settings.Secure.putString( + context.contentResolver, + Settings.Secure.NEARBY_SHARING_COMPONENT, + COMPONENT_NAME, + ) + whenever(activityInfo.loadLabel(any())).thenReturn("App") + controller.init(intent) + + assertThat(controller.isAvailable).isTrue() + } + + @Test + fun clickPreference_startActivity() { + Settings.Secure.putString( + context.contentResolver, + Settings.Secure.NEARBY_SHARING_COMPONENT, + COMPONENT_NAME, + ) + whenever(activityInfo.loadLabel(any())).thenReturn("App") + controller.init(intent) + doNothing().whenever(context).startActivity(any()) + val pref = + LayoutPreference( + context, + LayoutInflater.from(context).inflate(R.layout.nearby_sharing_suggestion_card, null), + ) + pref.key = PREF_KEY + mScreen.addPreference(pref) + controller.displayPreference(mScreen) + + pref.findViewById(R.id.card_container).performClick() + + verify(context).startActivity(intent) + } + + private companion object { + const val COMPONENT_NAME = "com.example/.BComponent" + const val PREF_KEY = "key" + } +} From 69a88812683c38832be9eabf1911a9c871d2cdd9 Mon Sep 17 00:00:00 2001 From: Garvita Jain Date: Fri, 21 Feb 2025 11:02:31 +0000 Subject: [PATCH 3/6] [Expressive Design] Migrate Storage settings dashboard for Work profile This change includes using SettingsLib.CardPreferenceWidget in storage dashboard for devices with work profile enabled. Test: manual BUG: 349670985 Flag: com.android.settingslib.widget.theme.flags.is_expressive_design_enabled Change-Id: Ib164df1f9d3507dd8d77d038210fe0eb0ca647c9 --- res/xml/storage_category_fragment.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/xml/storage_category_fragment.xml b/res/xml/storage_category_fragment.xml index 8af66396bd5..1742832df2a 100644 --- a/res/xml/storage_category_fragment.xml +++ b/res/xml/storage_category_fragment.xml @@ -19,7 +19,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/storage_settings"> - Date: Fri, 21 Feb 2025 09:49:17 +0000 Subject: [PATCH 4/6] Do not set title description for Confirm Activity The Confirm Lock Activity for Auto-Confirm feature announce redundant description after confirm the PIN/Password in the Click Toggle CUJ. 1. The title won't be present on the Confirm Lock 2. Set title for Confirm Lock breaks the a11y requirement Flag: EXEMPT for fixing a11y bug Bug: 384628809 Test: Manual enable a11y talkback, go to Settings > Security & Privacy > Device unlock > Screen lock > Settings > Auto-confirm unlock toggle > input PIN/Password to dismiss the confirm lock activity > Ensure no redundant title description announced by talkback Change-Id: I95fc03aae4fb5dc7500cc18c383dff62b95bc3f1 --- .../security/screenlock/AutoPinConfirmPreferenceController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java b/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java index 560f3134d66..673ff522116 100644 --- a/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java +++ b/src/com/android/settings/security/screenlock/AutoPinConfirmPreferenceController.java @@ -95,7 +95,6 @@ public class AutoPinConfirmPreferenceController extends AbstractPreferenceContro .setRequestCode(newState ? ScreenLockSettings.AUTO_PIN_SETTING_ENABLING_REQUEST_CODE : ScreenLockSettings.AUTO_PIN_SETTING_DISABLING_REQUEST_CODE) - .setTitle(mContext.getString(R.string.lock_screen_auto_pin_confirm_title)) .setDescription(newState ? mContext.getString(R.string.auto_confirm_on_pin_verify_description) : mContext.getString(R.string.auto_confirm_off_pin_verify_description)) From 125a6223af56c0f9336e9f6d8a33cbe695cca245 Mon Sep 17 00:00:00 2001 From: Owner Cleanup Bot Date: Sat, 22 Feb 2025 09:05:19 -0800 Subject: [PATCH 5/6] [owners] Remove zhangjerry@google.com from src/com/android/settings/connecteddevice/usb/OWNERS This suggested change is automatically generated based on group memberships and affiliations. Please approve this change and vote the highest CR. This will keep the OWNERs file tidy. We ask that you do not ignore this change and approve it unless you know a reason the OWNER should remain. It can always be reverted if needed. If this change is in error, vote the lowest CR value (i.e. reject the CL) and the bot will abandon it. See the owner's recent review activity for context: https://android-review.googlesource.com/q/zhangjerry@google.com To report an issue, file a bug in the Infra>Codereview component. Change-Id: Icfd162bf283cf74e3270d97a8ac15dcb2dfb34d3 --- src/com/android/settings/connecteddevice/usb/OWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/src/com/android/settings/connecteddevice/usb/OWNERS b/src/com/android/settings/connecteddevice/usb/OWNERS index bb3b8fcef67..60abfebf7c4 100644 --- a/src/com/android/settings/connecteddevice/usb/OWNERS +++ b/src/com/android/settings/connecteddevice/usb/OWNERS @@ -1,5 +1,4 @@ # Default reviewers for this and subdirectories. -zhangjerry@google.com badhri@google.com hughchen@google.com timhypeng@google.com From 04c7e27a7345ad0714fe9ba27b38179df47f4965 Mon Sep 17 00:00:00 2001 From: Chaohui Wang Date: Thu, 20 Feb 2025 13:21:49 +0800 Subject: [PATCH 6/6] Override isSpaExpressiveEnabled in Settings Into SettingsSpaEnvironment. Bug: 386013400 Flag: com.android.settingslib.widget.theme.flags.is_expressive_design_enabled Test: visual - expressive can enabled for spa in Settings Change-Id: I5225948c733a57855168a3e633fc4fbd4dd6f89a --- src/com/android/settings/spa/SettingsSpaEnvironment.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/com/android/settings/spa/SettingsSpaEnvironment.kt b/src/com/android/settings/spa/SettingsSpaEnvironment.kt index 7702db6bcde..754b30b5ab7 100644 --- a/src/com/android/settings/spa/SettingsSpaEnvironment.kt +++ b/src/com/android/settings/spa/SettingsSpaEnvironment.kt @@ -64,6 +64,7 @@ import com.android.settingslib.spa.framework.common.SpaLogger import com.android.settingslib.spa.framework.common.createSettingsPage import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListTemplate +import com.android.settingslib.widget.theme.flags.Flags open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { open fun getTogglePermissionAppListProviders(): List { @@ -132,4 +133,8 @@ open class SettingsSpaEnvironment(context: Context) : SpaEnvironment(context) { ) ) SpaLogMetricsProvider // ToDo: Implement 'SpaLogProvider' for SPA settings. else object : SpaLogger {} + + override val isSpaExpressiveEnabled by lazy { + super.isSpaExpressiveEnabled || Flags.isExpressiveDesignEnabled() + } }