diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index e653c63a507..80c3e8d2c4b 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1059,6 +1059,20 @@
- either_charging_or_docked
+
+ - @string/when_to_show_hubmode_never
+ - @string/when_to_show_hubmode_charging
+ - @string/when_to_show_hubmode_charging_and_upright
+ - @string/when_to_show_hubmode_docked
+
+
+
+ - never
+ - while_charging
+ - while_charging_and_upright
+ - while_docked
+
+
- @string/zen_mode_from_anyone
- @string/zen_mode_from_contacts
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 79020f903d0..7338c2f7abc 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3655,6 +3655,21 @@
Communal
Communal settings
+
+ Hub mode
+
+ Widgets on lock screen
+
+
+ When to automatically show
+
+ Never
+
+ While charging
+
+ While charging and upright
+
+ While docked
diff --git a/res/xml/display_settings.xml b/res/xml/display_settings.xml
index 9dc0bce18de..f839a477e8e 100644
--- a/res/xml/display_settings.xml
+++ b/res/xml/display_settings.xml
@@ -88,6 +88,12 @@
android:persistent="false"
android:title="@string/accessibility_text_reading_options_title"
settings:controller="com.android.settings.accessibility.TextReadingFragmentForDisplaySettingsController"/>
+
+
+
+
diff --git a/res/xml/widgets_on_lockscreen_settings.xml b/res/xml/widgets_on_lockscreen_settings.xml
new file mode 100644
index 00000000000..056df63ebd4
--- /dev/null
+++ b/res/xml/widgets_on_lockscreen_settings.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
diff --git a/src/com/android/settings/communal/CommunalPreferenceController.java b/src/com/android/settings/communal/CommunalPreferenceController.java
index e44afab90a6..16eb0e9dfc4 100644
--- a/src/com/android/settings/communal/CommunalPreferenceController.java
+++ b/src/com/android/settings/communal/CommunalPreferenceController.java
@@ -39,15 +39,14 @@ public class CommunalPreferenceController extends BasePreferenceController {
* Returns whether communal preferences are available.
*/
public static boolean isAvailable(Context context) {
+ if (com.android.systemui.Flags.glanceableHubV2()) {
+ return false;
+ }
+
if (!Utils.canCurrentUserDream(context)) {
return false;
}
- if (context.getResources().getBoolean(R.bool.config_show_communal_settings)) {
- return true;
- }
-
- return com.android.systemui.Flags.glanceableHubV2()
- && context.getResources().getBoolean(R.bool.config_show_communal_settings_mobile);
+ return context.getResources().getBoolean(R.bool.config_show_communal_settings);
}
}
diff --git a/src/com/android/settings/communal/WhenToStartHubPicker.java b/src/com/android/settings/communal/WhenToStartHubPicker.java
new file mode 100644
index 00000000000..59233257a30
--- /dev/null
+++ b/src/com/android/settings/communal/WhenToStartHubPicker.java
@@ -0,0 +1,179 @@
+/*
+ * 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.communal;
+
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING;
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING_UPRIGHT;
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_DOCKED;
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_NEVER;
+import static android.provider.Settings.Secure.WHEN_TO_START_GLANCEABLE_HUB;
+
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.provider.Settings;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.settings.R;
+import com.android.settings.widget.RadioButtonPickerFragment;
+import com.android.settingslib.widget.CandidateInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment that provides radio buttons to allow the user to choose when the hub should auto-start.
+ */
+public class WhenToStartHubPicker extends RadioButtonPickerFragment {
+ private static final String TAG = "WhenToStartHubPicker";
+ private static final String SHOW_WHILE_CHARGING = "while_charging";
+ private static final String SHOW_WHILE_DOCKED = "while_docked";
+ private static final String SHOW_WHILE_CHARGING_AND_UPRIGHT = "while_charging_and_upright";
+ private static final String SHOW_NEVER = "never";
+
+ private Context mContext;
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+
+ mContext = context;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.when_to_start_hubmode_settings;
+ }
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.WHEN_TO_SHOW_WIDGETS_ON_LOCKSCREEN;
+ }
+
+ @Override
+ protected List extends CandidateInfo> getCandidates() {
+ final List candidates = new ArrayList<>();
+
+ final String[] entries = entries();
+ final String[] values = keys();
+
+ if (entries == null || entries.length <= 0) return candidates;
+ if (values == null || values.length != entries.length) {
+ throw new IllegalArgumentException("Entries and values must be of the same length.");
+ }
+
+ for (int i = 0; i < entries.length; i++) {
+ candidates.add(new WhenToStartHubCandidateInfo(entries[i], values[i]));
+ }
+
+ return candidates;
+ }
+
+ private String[] entries() {
+ return getResources().getStringArray(R.array.when_to_start_hubmode_entries);
+ }
+
+ private String[] keys() {
+ return getResources().getStringArray(R.array.when_to_start_hubmode_values);
+ }
+
+ @Override
+ protected String getDefaultKey() {
+ final int defaultValue = mContext.getResources().getInteger(
+ com.android.internal.R.integer.config_whenToStartHubModeDefault);
+ final int setting = Settings.Secure.getInt(
+ mContext.getContentResolver(), WHEN_TO_START_GLANCEABLE_HUB, defaultValue);
+ return getKeyFromSetting(setting);
+ }
+
+ @Override
+ protected boolean setDefaultKey(String key) {
+ Settings.Secure.putInt(
+ mContext.getContentResolver(),
+ WHEN_TO_START_GLANCEABLE_HUB,
+ getSettingFromPrefKey(key));
+
+ return true;
+ }
+
+ @Override
+ protected void onSelectionPerformed(boolean success) {
+ super.onSelectionPerformed(success);
+
+ getActivity().finish();
+ }
+
+
+ @Settings.Secure.WhenToStartGlanceableHub
+ private static int getSettingFromPrefKey(String key) {
+ switch (key) {
+ case SHOW_WHILE_CHARGING:
+ return GLANCEABLE_HUB_START_CHARGING;
+ case SHOW_WHILE_DOCKED:
+ return GLANCEABLE_HUB_START_DOCKED;
+ case SHOW_WHILE_CHARGING_AND_UPRIGHT:
+ return GLANCEABLE_HUB_START_CHARGING_UPRIGHT;
+ case SHOW_NEVER:
+ default:
+ return GLANCEABLE_HUB_START_NEVER;
+ }
+ }
+
+ private static String getKeyFromSetting(@Settings.Secure.WhenToStartGlanceableHub int setting) {
+ switch (setting) {
+ case GLANCEABLE_HUB_START_CHARGING:
+ return SHOW_WHILE_CHARGING;
+ case GLANCEABLE_HUB_START_DOCKED:
+ return SHOW_WHILE_DOCKED;
+ case GLANCEABLE_HUB_START_CHARGING_UPRIGHT:
+ return SHOW_WHILE_CHARGING_AND_UPRIGHT;
+ case GLANCEABLE_HUB_START_NEVER:
+ default:
+ return SHOW_NEVER;
+ }
+ }
+
+ private static final class WhenToStartHubCandidateInfo extends CandidateInfo {
+ private final String mName;
+ private final String mKey;
+
+ WhenToStartHubCandidateInfo(String title, String value) {
+ super(true);
+
+ mName = title;
+ mKey = value;
+ }
+
+ @Override
+ public CharSequence loadLabel() {
+ return mName;
+ }
+
+ @Override
+ @Nullable
+ public Drawable loadIcon() {
+ return null;
+ }
+
+ @Override
+ public String getKey() {
+ return mKey;
+ }
+ }
+}
diff --git a/src/com/android/settings/communal/WhenToStartHubPreferenceController.java b/src/com/android/settings/communal/WhenToStartHubPreferenceController.java
new file mode 100644
index 00000000000..67931ee7f65
--- /dev/null
+++ b/src/com/android/settings/communal/WhenToStartHubPreferenceController.java
@@ -0,0 +1,81 @@
+/*
+ * 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.communal;
+
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING;
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_CHARGING_UPRIGHT;
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_DOCKED;
+import static android.provider.Settings.Secure.GLANCEABLE_HUB_START_NEVER;
+import static android.provider.Settings.Secure.WHEN_TO_START_GLANCEABLE_HUB;
+
+import android.annotation.StringRes;
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.PreferenceControllerMixin;
+
+/**
+ * A preference controller that is responsible for showing the "when to auto start hub" setting in
+ * hub settings.
+ */
+public class WhenToStartHubPreferenceController extends BasePreferenceController implements
+ PreferenceControllerMixin {
+ public WhenToStartHubPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public void updateState(Preference preference) {
+ super.updateState(preference);
+
+ preference.setSummary(getSummaryResId());
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return mContext.getString(getSummaryResId());
+ }
+
+ @StringRes
+ private int getSummaryResId() {
+ final int setting = Settings.Secure.getInt(
+ mContext.getContentResolver(),
+ WHEN_TO_START_GLANCEABLE_HUB,
+ GLANCEABLE_HUB_START_NEVER);
+
+ switch (setting) {
+ case GLANCEABLE_HUB_START_CHARGING:
+ return R.string.when_to_show_hubmode_charging;
+ case GLANCEABLE_HUB_START_DOCKED:
+ return R.string.when_to_show_hubmode_docked;
+ case GLANCEABLE_HUB_START_CHARGING_UPRIGHT:
+ return R.string.when_to_show_hubmode_charging_and_upright;
+ case GLANCEABLE_HUB_START_NEVER:
+ default:
+ return R.string.when_to_show_hubmode_never;
+ }
+ }
+}
diff --git a/src/com/android/settings/communal/WidgetsOnLockscreenFragment.java b/src/com/android/settings/communal/WidgetsOnLockscreenFragment.java
new file mode 100644
index 00000000000..09a1e4d1c3e
--- /dev/null
+++ b/src/com/android/settings/communal/WidgetsOnLockscreenFragment.java
@@ -0,0 +1,50 @@
+/*
+ * 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.communal;
+
+import android.app.settings.SettingsEnums;
+
+import com.android.settings.R;
+import com.android.settings.dashboard.DashboardFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settingslib.search.SearchIndexable;
+
+/**
+ * Fragment that contains settings related to communal hub.
+ */
+@SearchIndexable
+public class WidgetsOnLockscreenFragment extends DashboardFragment {
+ private static final String TAG = "WidgetsOnLockscreenFragment";
+
+ @Override
+ public int getMetricsCategory() {
+ return SettingsEnums.WIDGETS_ON_LOCK_SCREEN;
+ }
+
+ @Override
+ protected int getPreferenceScreenResId() {
+ return R.xml.widgets_on_lockscreen_settings;
+ }
+
+ @Override
+ protected String getLogTag() {
+ return TAG;
+ }
+
+ public static final BaseSearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider(R.xml.widgets_on_lockscreen_settings);
+}
diff --git a/src/com/android/settings/display/WidgetsOnLockscreenPreferenceController.java b/src/com/android/settings/display/WidgetsOnLockscreenPreferenceController.java
new file mode 100644
index 00000000000..32ba6ec5c23
--- /dev/null
+++ b/src/com/android/settings/display/WidgetsOnLockscreenPreferenceController.java
@@ -0,0 +1,55 @@
+/*
+ * 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.display;
+
+import android.content.Context;
+import android.os.UserHandle;
+import android.os.UserManager;
+
+import com.android.settings.R;
+import com.android.settings.core.BasePreferenceController;
+
+/** Controls the "widgets on lock screen" preferences (under "Display & touch"). */
+public class WidgetsOnLockscreenPreferenceController extends BasePreferenceController {
+ public WidgetsOnLockscreenPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return isAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+ }
+
+ /**
+ * Returns whether "widgets on lock screen" preferences are available.
+ */
+ public static boolean isAvailable(Context context) {
+ if (!isMainUser(context)) {
+ return false;
+ }
+
+ return com.android.systemui.Flags.glanceableHubV2()
+ && (context.getResources().getBoolean(R.bool.config_show_communal_settings)
+ || context.getResources().getBoolean(
+ R.bool.config_show_communal_settings_mobile));
+ }
+
+ private static boolean isMainUser(Context context) {
+ final UserManager userManager = context.getSystemService(UserManager.class);
+ return userManager.getUserInfo(UserHandle.myUserId()).isMain();
+ }
+}
diff --git a/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java
index cc970eb6b1d..17a51794ebc 100644
--- a/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java
+++ b/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java
@@ -16,11 +16,8 @@
package com.android.settings.communal;
-import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2;
-import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -66,6 +63,7 @@ public class CommunalPreferenceControllerTest {
}
@Test
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
public void isAvailable_communalEnabled_shouldBeTrueForPrimaryUser() {
setCommunalEnabled(true);
mShadowUserManager.setUserForeground(true);
@@ -73,6 +71,7 @@ public class CommunalPreferenceControllerTest {
}
@Test
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
public void isAvailable_communalEnabled_shouldBeFalseForSecondaryUser() {
setCommunalEnabled(true);
mShadowUserManager.setUserForeground(false);
@@ -80,6 +79,7 @@ public class CommunalPreferenceControllerTest {
}
@Test
+ @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
public void isAvailable_communalDisabled_shouldBeFalseForPrimaryUser() {
setCommunalEnabled(false);
mShadowUserManager.setUserForeground(true);
@@ -88,36 +88,8 @@ public class CommunalPreferenceControllerTest {
@Test
@EnableFlags(FLAG_GLANCEABLE_HUB_V2)
- public void isAvailable_communalOnMobileEnabled_shouldBeTrueForPrimaryUser() {
- setCommunalEnabled(false);
- setCommunalOnMobileEnabled(true);
- mShadowUserManager.setUserForeground(true);
- assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
- }
-
- @Test
- @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
- public void isAvailable_communalOnMobileEnabled_shouldBeFalseForSecondaryUser() {
- setCommunalEnabled(false);
- setCommunalOnMobileEnabled(true);
- mShadowUserManager.setUserForeground(false);
- assertFalse(mController.isAvailable());
- }
-
- @Test
- @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
- public void isAvailable_communalOnMobileDisabled_shouldBeFalseForPrimaryUser() {
- setCommunalEnabled(false);
- setCommunalOnMobileEnabled(false);
- mShadowUserManager.setUserForeground(true);
- assertFalse(mController.isAvailable());
- }
-
- @Test
- @DisableFlags(FLAG_GLANCEABLE_HUB_V2)
- public void isAvailable_glanceableHubV2FlagDisabled_shouldBeFalseForPrimaryUser() {
- setCommunalEnabled(false);
- setCommunalOnMobileEnabled(true);
+ public void isAvailable_glanceableHubV2Enabled_shouldBeFalseForPrimaryUser() {
+ setCommunalEnabled(true);
mShadowUserManager.setUserForeground(true);
assertFalse(mController.isAvailable());
}
@@ -125,9 +97,4 @@ public class CommunalPreferenceControllerTest {
private void setCommunalEnabled(boolean enabled) {
SettingsShadowResources.overrideResource(R.bool.config_show_communal_settings, enabled);
}
-
- private void setCommunalOnMobileEnabled(boolean enabled) {
- SettingsShadowResources.overrideResource(
- R.bool.config_show_communal_settings_mobile, enabled);
- }
}