Skip to content

feat: multi icon support#2396

Draft
RohitKushvaha01 wants to merge 1 commit into
Acode-Foundation:mainfrom
RohitKushvaha01:feat/multi-icon-support
Draft

feat: multi icon support#2396
RohitKushvaha01 wants to merge 1 commit into
Acode-Foundation:mainfrom
RohitKushvaha01:feat/multi-icon-support

Conversation

@RohitKushvaha01

Copy link
Copy Markdown
Member

No description provided.

@greptile-apps

greptile-apps Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds multi-icon support for the Android launcher, allowing users to switch between the default Acode icon and an alternate icon (ic_alt) via new getAppIcons/setAppIcon native plugin methods. It also reformats config.xml, fixes the changeProvider.js regex to handle the reformatted XML, and removes a redundant Cordova plugin variable for the TLS blacklist.

  • New Java methods in System.java query all MAIN/LAUNCHER components and toggle enabled/disabled state via PackageManager.setComponentEnabledSetting to switch the visible launcher icon.
  • config.xml adds a single activity-alias (MainActivityAlt1) pointing at the alternate icon resource @drawable/ic_alt.
  • TypeScript declarations expose the new API but setAppIcon's onSuccess is typed as OnSuccessBool while the Java side calls callbackContext.success() with no argument.

Confidence Score: 3/5

Not safe to merge — switching to the alternate icon disables MainActivity itself, which can make the app unlaunchable from the home screen.

The setAppIcon logic disables MainActivity when an alias is selected. Because Android activity-alias entries require their targetActivity to remain enabled, this leaves the app unable to start from the launcher after switching icons. A second independent issue in the TypeScript declaration types the success callback incorrectly, though that only affects callers who inspect the result. The core icon-switching logic needs a redesign before this can be merged safely.

System.java (the setAppIcon method) and config.xml (how MainActivity's launcher intent-filter interacts with the alias) need the most attention.

Important Files Changed

Filename Overview
src/plugins/system/android/com/foxdebug/system/System.java Adds getAppIcons and setAppIcon Java methods; setAppIcon has a critical logic flaw where it disables MainActivity when switching to an alias, making the app unlaunchable. Minor indentation inconsistency in new switch cases.
src/plugins/system/system.d.ts Adds getAppIcons and setAppIcon type declarations and AppIcon interface; setAppIcon's onSuccess is typed as OnSuccessBool but Java sends no-arg success, causing callers to receive null instead of a boolean.
src/plugins/system/www/plugin.js Adds thin JS wrappers for getAppIcons and setAppIcon that correctly delegate to cordova.exec.
config.xml Reformatted for readability and adds a single activity-alias (MainActivityAlt1) for the alternate launcher icon; MainActivity itself retains the MAIN/LAUNCHER intent-filter, which interacts poorly with the setAppIcon disable logic.
src/plugins/system/utils/changeProvider.js Fixes the widget id regex to handle whitespace after widget, accommodating the reformatted config.xml.
package.json Removes the redundant ANDROIDBLACKLISTSECURESOCKETPROTOCOLS plugin variable; the same protocol blacklist is already declared as a Cordova preference in config.xml.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant JS as plugin.js
    participant Java as System.java
    participant PM as PackageManager

    JS->>Java: setAppIcon(".MainActivityAlt1")
    Java->>PM: queryIntentActivities(MAIN/LAUNCHER)
    PM-->>Java: [MainActivity, MainActivityAlt1]
    Java->>Java: verify target exists
    Java->>PM: setComponentEnabledSetting(MainActivityAlt1, ENABLED)
    Java->>PM: setComponentEnabledSetting(MainActivity, DISABLED) ⚠️
    Java-->>JS: callbackContext.success() [null, not boolean]

    JS->>Java: getAppIcons()
    Java->>PM: queryIntentActivities(MAIN/LAUNCHER, MATCH_DISABLED_COMPONENTS)
    PM-->>Java: [MainActivity, MainActivityAlt1]
    Java->>Java: build JSONArray with name/label/icon/enabled
    Java-->>JS: success(JSONArray)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant JS as plugin.js
    participant Java as System.java
    participant PM as PackageManager

    JS->>Java: setAppIcon(".MainActivityAlt1")
    Java->>PM: queryIntentActivities(MAIN/LAUNCHER)
    PM-->>Java: [MainActivity, MainActivityAlt1]
    Java->>Java: verify target exists
    Java->>PM: setComponentEnabledSetting(MainActivityAlt1, ENABLED)
    Java->>PM: setComponentEnabledSetting(MainActivity, DISABLED) ⚠️
    Java-->>JS: callbackContext.success() [null, not boolean]

    JS->>Java: getAppIcons()
    Java->>PM: queryIntentActivities(MAIN/LAUNCHER, MATCH_DISABLED_COMPONENTS)
    PM-->>Java: [MainActivity, MainActivityAlt1]
    Java->>Java: build JSONArray with name/label/icon/enabled
    Java-->>JS: success(JSONArray)
Loading

Reviews (1): Last reviewed commit: "feat: multi icon support" | Re-trigger Greptile

Comment on lines +2261 to +2278
} else {
flags |= PackageManager.GET_DISABLED_COMPONENTS;
}

List<ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, flags);

String target = targetComponentName;
if (target.startsWith(".")) {
target = context.getPackageName() + target;
}

boolean found = false;

// First pass: verify if targetComponentName is a valid launcher component
for (ResolveInfo info : resolveInfos) {
if (info.activityInfo.name.equals(target)) {
found = true;
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 setAppIcon disables MainActivity, making the app unlaunchable when an alias is active

The second pass iterates every entry returned by queryIntentActivities(MAIN/LAUNCHER) and disables all components that are not the target. MainActivity itself has a MAIN+LAUNCHER intent-filter (standard Cordova setup), so it appears in this list. When .MainActivityAlt1 is selected, MainActivity gets COMPONENT_ENABLED_STATE_DISABLED. Because an activity-alias always delegates to its targetActivity, Android requires the target to be enabled — a disabled MainActivity means MainActivityAlt1 can no longer launch the app, effectively making it unlaunchable from the home screen.

The standard pattern for icon switching is: (1) remove the MAIN/LAUNCHER intent-filter from MainActivity itself, (2) add a "default" activity-alias for the original icon, and (3) only ever toggle aliases — never touch MainActivity directly with setComponentEnabledSetting.

* @param onSuccess
* @param onFail
*/
setAppIcon(componentName: string, onSuccess: OnSuccessBool, onFail: OnFail): void;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 setAppIcon declares onSuccess: OnSuccessBool ((res: boolean) => void), but the Java implementation calls callbackContext.success() with no argument, so the callback always receives null. Any caller that checks res in the callback will always see null, not a boolean. The callback signature should match the no-arg void pattern used by similar write-only operations like setNativeContextMenuDisabled.

Suggested change
setAppIcon(componentName: string, onSuccess: OnSuccessBool, onFail: OnFail): void;
setAppIcon(componentName: string, onSuccess: () => void, onFail: OnFail): void;

Comment on lines +579 to +587
case "get-app-info":
getAppInfo(callbackContext);
break;
case "get-app-icons":
getAppIcons(callbackContext);
break;
case "set-app-icon":
setAppIcon(arg1, callbackContext);
break;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 The three new/modified case blocks have an extra leading space compared to the surrounding case "pin-file-shortcut" and others (29 spaces vs 28). This creates an inconsistent indentation in an otherwise uniform switch block.

Suggested change
case "get-app-info":
getAppInfo(callbackContext);
break;
case "get-app-icons":
getAppIcons(callbackContext);
break;
case "set-app-icon":
setAppIcon(arg1, callbackContext);
break;
case "get-app-info":
getAppInfo(callbackContext);
break;
case "get-app-icons":
getAppIcons(callbackContext);
break;
case "set-app-icon":
setAppIcon(arg1, callbackContext);
break;

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@RohitKushvaha01 RohitKushvaha01 marked this pull request as draft June 26, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

1 participant