-
Notifications
You must be signed in to change notification settings - Fork 0
settings
How the launcher's Settings page is structured, navigated, and how preference changes propagate back to the launcher.
Users reach Settings by long-pressing the workspace background, which opens an options popup. The "Home settings" item is wired up in OptionsPopupView.java:
// OptionsPopupView.java, getOptions()
options.add(new OptionItem(launcher,
R.string.settings_button_text,
R.drawable.ic_setting,
LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS,
OptionsPopupView::startSettings));The startSettings() method fires an ACTION_APPLICATION_PREFERENCES intent scoped to the launcher's own package. This is the standard Android mechanism for opening app preferences.
File: src/com/android/launcher3/settings/SettingsActivity.java
The activity extends AppCompatActivity (migrated from AOSP's FragmentActivity) and implements:
-
OnPreferenceStartFragmentCallback-- handles clicks on preferences that specify afragmentattribute -
OnPreferenceStartScreenCallback-- handles drilling into nestedPreferenceScreennodes
The activity theme is HomeSettings.Theme, which extends Theme.Material3.DayNight.NoActionBar. DynamicColors.applyToActivityIfAvailable(this) is called before super.onCreate() to pick up the device's wallpaper-extracted color palette.
Declared in AndroidManifest-common.xml (the shared manifest merged into all build variants):
<activity
android:name="com.android.launcher3.settings.SettingsActivity"
android:label="@string/settings_title"
android:theme="@style/HomeSettings.Theme"
android:exported="true"
android:autoRemoveFromRecents="true">
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>-
exported="true"so system Settings search can launch it directly -
autoRemoveFromRecents="true"keeps the recents list clean
| API Level | Layout File | Design |
|---|---|---|
| Default | res/layout/settings_activity.xml |
LinearLayout with MaterialToolbar + FrameLayout content area |
| 31+ | res/layout-v31/settings_activity.xml |
CoordinatorLayout with collapsing AppBarLayout / CollapsingToolbarLayout for M3 header |
Both layouts use com.google.android.material.appbar.MaterialToolbar (not the legacy Toolbar), paired with setSupportActionBar().
The CollapsingToolbarLayout displays "Default" in Danfo font:
CollapsingToolbarLayout collapsingToolbar = findViewById(R.id.collapsing_toolbar);
collapsingToolbar.setTitle(getString(R.string.settings_title));
Typeface danfo = getResources().getFont(R.font.danfo);
collapsingToolbar.setCollapsedTitleTypeface(danfo);
collapsingToolbar.setExpandedTitleTypeface(danfo);Key: the font is set via setCollapsedTitleTypeface() / setExpandedTitleTypeface(), not via text appearance styles or SpannableString. CollapsingTextHelper (the internal renderer) ignores TypefaceSpan and android:fontFamily from text appearances -- only the dedicated typeface setters work.
The background transition uses the CTL's native contentScrim:
app:contentScrim="@color/materialColorSurfaceContainer"No custom OnOffsetChangedListener needed -- the CTL handles the fade between transparent (expanded) and surface container (collapsed). app:liftOnScroll="false" is set on the AppBarLayout to prevent M3's default elevation tint from conflicting.
The activity does not hardcode its fragment class. Instead it reads from a string resource:
// SettingsActivity.java, onCreate()
final Fragment f = fm.getFragmentFactory().instantiate(
getClassLoader(),
getString(R.string.settings_fragment_name));The resource settings_fragment_name is defined in res/values/config.xml:
<string name="settings_fragment_name" translatable="false">
com.android.launcher3.settings.SettingsActivity$LauncherSettingsFragment
</string>This is a deliberate extension point -- derivative launchers (Go edition, OEM forks) can override this resource to swap in a different fragment without changing Java code.
An inner static class inside SettingsActivity.java. Extends PreferenceFragmentCompat and implements SettingsCache.OnChangeListener.
Preferences are defined in res/xml/launcher_preferences.xml:
| Key | Type | Description |
|---|---|---|
pref_icon_badging |
NotificationDotsPreference (custom) |
Notification dots on/off status |
pref_icon_pack |
Preference |
Icon pack picker (opens bottom sheet) |
pref_icon_shape |
Preference |
Icon shape picker (opens bottom sheet) |
pref_icon_size_scale |
Preference (custom layout) |
Icon size with inline toggle group |
pref_grid_columns |
M3SliderPreference (custom) |
Grid column count (4-10) |
pref_allapps_row_gap |
M3SliderPreference (custom) |
App drawer row gap in dp |
Preferences are organized into categories:
- Appearance -- notification dots, icon pack, icon shape, icon size
- Grid -- column count, app drawer row gap
- Theme colors -- color debug swatch grid
The settings list uses a Lawnchair-style card group layout via CardGroupItemDecoration, a RecyclerView.ItemDecoration that:
- Draws individual rounded-rect backgrounds per preference item
- Uses position-aware corner radii (large top corners for first item, large bottom for last)
- Leaves category headers outside the cards with no background
- Separates items with a 4dp gap (no divider lines)
| Class | Purpose |
|---|---|
M3SliderPreference |
Replaces SeekBarPreference with a Material 3 Slider. Hides the default widget area and injects its own Slider + value label into onBindViewHolder. |
ColorDebugPreference |
Displays a grid of dynamic color swatches using materialColor* resources. Useful for verifying M3 dynamic color integration. |
NotificationDotsPreference |
Reflects system Settings.Secure.notification_badging state (not persisted locally). |
The icon size preference uses a custom layout (res/layout/preference_icon_size.xml) with a MaterialButtonToggleGroup embedded directly in the preference row. The toggle group is bound via RecyclerView.OnChildAttachStateChangeListener in onViewCreated():
rv.addOnChildAttachStateChangeListener(new OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(View child) {
if (child.findViewById(R.id.size_toggle_group) != null) {
bindIconSizeInline(child);
}
}
});Presets: S (80%), M (86%), L (92%), XL (100%). A star button opens a MaterialAlertDialogBuilder dialog for custom percentage input. Button selection animates corner radii from inner-group shape to pill shape.
The initPreference() method iterates every preference from the XML and returns false to remove ones that don't apply:
| Key | Removed When |
|---|---|
pref_icon_badging |
NOTIFICATION_DOTS_ENABLED build config is false
|
pref_developer_options |
Not a debug device, OR system developer options disabled |
pref_fixed_landscape_mode |
Flags.oneGridSpecs() is false, OR device is tablet/multi-display |
The fragment explicitly sets its preferences file:
getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);Where SHARED_PREFERENCES_KEY = "com.android.launcher3.prefs" (from LauncherFiles.java).
When a preference has a fragment attribute, the activity's onPreferenceStartFragment() handles it. The startPreference() method has a key design decision:
private boolean startPreference(String fragment, Bundle args, String key) {
if (f instanceof DialogFragment) {
((DialogFragment) f).show(fm, key); // dialog overlay
} else {
startActivity(new Intent(this, SettingsActivity.class) // new activity instance
.putExtra(EXTRA_FRAGMENT_ARGS, args));
}
}- DialogFragments are shown as overlays on the current activity
-
Everything else launches a new
SettingsActivityinstance. This works with Activity Embedding (configured inres/xml/split_configuration.xml) to show a side-by-side split on large screens.
The activity supports jumping directly to a specific preference via intent extras:
-
EXTRA_FRAGMENT_ROOT_KEY-- whichPreferenceScreento show as root -
EXTRA_FRAGMENT_HIGHLIGHT_KEY-- which preference to scroll to and highlight
The visual highlight is handled by PreferenceHighlighter.java, which draws a pulsing accent-colored rectangle over the target preference using RecyclerView.ItemDecoration.
Settings changes reach the launcher through four mechanisms:
No listener. Value is read when needed.
- Example:
pref_add_icon_to_homechecked bySessionCommitReceiver
LauncherPrefs.kt provides typed preference access with listener management:
fun addListener(listener: LauncherPrefChangeListener, vararg items: Item)The LauncherPrefChangeListener interface wraps Android's OnSharedPreferenceChangeListener.
Consumers:
-
RotationHelperlistens forALLOW_ROTATION -
InvariantDeviceProfilelistens forFIXED_LANDSCAPE_MODE
SettingsCache.java is a ContentObserver singleton that caches boolean values from Settings.Secure, Settings.System, and Settings.Global, and dispatches OnChangeListener callbacks when they change.
Monitored URIs include:
-
NOTIFICATION_BADGING_URI(Settings.Secure.notification_badging) -
ROTATION_SETTING_URI(system auto-rotate) - Developer options state (
Settings.Global.development_settings_enabled)
When developer options state changes while the settings activity is open, tryRecreateActivity() calls activity.recreate() to reflect the new state (show/hide the developer options entry).
Dynamic M3 colors are defined in res/values-v31/colors.xml (light) and res/values-night-v31/colors.xml (dark), mapped to Android's system_accent1/2/3 and system_neutral1/2 palette slots. Key resources used throughout settings and launcher themes:
| Resource | Light Source | Usage |
|---|---|---|
materialColorSurfaceContainer |
system_neutral1_100 |
Toolbar collapsed bg, search bar bg, popup bg |
materialColorOnSurface |
system_neutral1_900 |
Primary text color |
materialColorOnSurfaceVariant |
system_neutral2_700 |
Search hint text, search icon tint |
materialColorPrimary |
system_accent1_600 |
Category title color, accent |
materialColorOutlineVariant |
system_neutral2_200 |
Popup tertiary color |
Settings UI uses M3 Expressive type tokens:
| Element | Style | Specs |
|---|---|---|
| Preference title | TextAppearance.Material3.BodyLarge |
16sp / 400 weight |
| Preference summary | (default) TextAppearance.Material3.BodyMedium
|
14sp / 400 weight |
| Category header | TextAppearance.Material3.TitleSmall |
colored with ?attr/colorPrimary
|
| Toolbar collapsed | TextAppearance.Material3.TitleLarge |
20sp, Danfo |
| Toolbar expanded | TextAppearance.Material3.DisplaySmall |
Danfo |
| File | Role |
|---|---|
SettingsActivity.java |
Activity + LauncherSettingsFragment |
CardGroupItemDecoration.java |
Lawnchair-style rounded card groups |
M3SliderPreference.java |
Material 3 slider replacing SeekBarPreference |
ColorDebugPreference.java |
Dynamic color swatch grid |
NotificationDotsPreference.java |
Custom preference for notification dots |
PreferenceHighlighter.java |
Visual highlight animation for deep-linked preferences |
launcher_preferences.xml |
Preference hierarchy definition |
preference_icon_size.xml |
Inline icon size toggle layout |
settings_activity.xml |
Base layout |
settings_activity.xml (v31) |
API 31+ layout with collapsing toolbar |
dancing_script.ttf |
Toolbar title font |
AndroidManifest-common.xml |
Activity declaration |
split_configuration.xml |
Activity Embedding rules for large screens |
config.xml |
settings_fragment_name extension point |
LauncherPrefs.kt |
Typed SharedPreferences with listener support |
LauncherPrefChangeListener.java |
Preference change callback interface |
SettingsCache.java |
ContentObserver cache for system settings |
RotationHelper.java |
Consumes allow-rotation preference |
SessionCommitReceiver.java |
Consumes add-icon-to-home preference |
InvariantDeviceProfile.java |
Consumes fixed-landscape-mode preference |
OptionsPopupView.java |
Long-press menu that launches settings |
LauncherFiles.java |
SharedPreferences file name constants |
Architecture
Guides
Changes
- 031 App Icon & Clipping Fix
- 030 Folder Refactoring
- 029 Folder Features
- 028 Settings Polish
- 027 M3 Expressive
- 026 Code Quality
- 025 Wallpaper Scroll
- 024 Dead Code Cleanup
- 023 Search Perf
- 022 Settings Colors
- 021 Render Overrides
- 020 Per-App Icons
- 019 Toolbar & Preview
- 018 Colors Reorg
- 017 Search Animation
- 016 Universal Search
- 015 App Visibility
- 014 Settings Polish
- 013 Drawer Colors Fix
- 012 Drawer Colors
- 011 Notification Shade
- 010 Drawer Labels
- 009 M3 Drawer
- 008 M3 Settings
- 007 Icon Size
- 006 Icon Packs
- 005 Drawer Cleanup
- 004 Defaults & Gaps
- 003 Grid Reflow
- 002 Hotseat Row
- 001 Square Grid