I had ai write it up
Issue 1: Settings crashes when opening the Voice Access screen
In ToggleFeaturePreferenceFragment.onViewCreated(), a PreferenceCategory (key general_categories) is created and configured, but never attached to the fragment’s PreferenceScreen before another preference is added into it. Adding a child to an unattached PreferenceGroup throws a NullPointerException in PreferenceManager.getNextId().
File: smali/com/android/settings/accessibility/ToggleFeaturePreferenceFragment.smali
Method: onViewCreated(Landroid/view/View;Landroid/os/Bundle;)V
Fix: Insert a call to attach the category to the screen (p1) right after it’s titled, before initShortcutPreference is called:
sget v2, Lcom/android/settings/R$string;->accessibility_screen_option:I
invoke-virtual {v0, v2}, Landroidx/preference/Preference;->setTitle(I)V
invoke-virtual {p1, v0}, Landroidx/preference/PreferenceGroup;->addPreference(Landroidx/preference/Preference;)Z
invoke-direct {p0, p2}, Lcom/android/settings/accessibility/ToggleFeaturePreferenceFragment;->initShortcutPreference(Landroid/os/Bundle;)V
(Only the addPreference line is new, the lines around it already exist and are shown for placement reference.)
Issue 2: No toggle switch appears on the Voice Access screen
Cause: Settings classifies every accessibility service into one of 3 fragment types via AccessibilityUtil.getAccessibilityServiceFragmentType(), based on targetSdkVersion and whether the service declares the accessibility-button flag. Voice Access was being classified as “Invisible Toggle” (no switch shown, expects shortcut-only interaction) instead of the normal “Toggle” type.
File: smali/com/android/settings/accessibility/AccessibilityUtil.smali
Method: getAccessibilityServiceFragmentType(Landroid/accessibilityservice/AccessibilityServiceInfo;)I
Fix: Replace the entire method body to always return type 2 (normal Toggle) for every accessibility service:
.method static getAccessibilityServiceFragmentType(Landroid/accessibilityservice/AccessibilityServiceInfo;)I
.registers 5
const/4 v1, 0x2
return v1
.end method
Note: this device has no volume keys, so forcing away the “Volume Shortcut Toggle” classification (type 0) has no downside here.
Issue 3: Settings crashes when actually flipping the toggle on
Cause: Enabling the toggle triggers a tutorial dialog showing the accessibility-shortcut gesture animation. AccessibilityGestureNavigationTutorial.createShortcutNavigationContentView() builds this content based on the device’s navigation mode, and an internal Preconditions.checkArgument() throws IllegalArgumentException: Unexpected tutorial pages size — this device’s nav mode doesn’t produce a page count the check expects.
File: smali/com/android/settings/accessibility/AccessibilityGestureNavigationTutorial.smali
Method: createAccessibilityTutorialDialog(Landroid/content/Context;I)Landroidx/appcompat/app/AlertDialog;
Fix: Delete the 3 lines that build and attach the crashing content view, leaving the dialog’s title/button/creation intact:
Remove:
invoke-static {p0, p1}, Lcom/android/settings/accessibility/AccessibilityGestureNavigationTutorial;->createShortcutNavigationContentView(Landroid/content/Context;I)Landroid/view/View;
move-result-object p0
invoke-virtual {v0, p0}, Landroidx/appcompat/app/AlertDialog$Builder;->setView(Landroid/view/View;)Landroidx/appcompat/app/AlertDialog$Builder;
Resulting method:
.method static createAccessibilityTutorialDialog(Landroid/content/Context;I)Landroidx/appcompat/app/AlertDialog;
.registers 3
new-instance v0, Landroidx/appcompat/app/AlertDialog$Builder;
invoke-direct {v0, p0}, Landroidx/appcompat/app/AlertDialog$Builder;-><init>(Landroid/content/Context;)V
sget p0, Lcom/android/settings/R$string;->accessibility_tutorial_dialog_button:I
sget-object p1, Lcom/android/settings/accessibility/AccessibilityGestureNavigationTutorial;->mOnClickListener:Landroid/content/DialogInterface$OnClickListener;
invoke-virtual {v0, p0, p1}, Landroidx/appcompat/app/AlertDialog$Builder;->setNegativeButton(ILandroid/content/DialogInterface$OnClickListener;)Landroidx/appcompat/app/AlertDialog$Builder;
invoke-virtual {v0}, Landroidx/appcompat/app/AlertDialog$Builder;->create()Landroidx/appcompat/app/AlertDialog;
move-result-object p0
return-object p0
.end method
This produces a minimal dialog (dismiss button only, no tutorial illustration) instead of crashing. onCreateDialog in both ToggleFeaturePreferenceFragment and ToggleAccessibilityServicePreferenceFragment call into this method but don’t need any changes themselves.