Change Android Launcher Icon like Instagram/Todoist
Asked Answered
C

1

5

At Instagrams anniversary the users were possible to change the app icon. Even though this feature isn't available anymore Todoist has a similar working implementation of this feature.

I researched how to achieve this and got the second answer running: change application icon.

But this solution seems to come with drawbacks which I don't want. Some of these are listed here under the notes: blog change app icon. Furthermore, by using this solution my App gets killed every time I choose another icon with the activity-alias and I wasn't able to keep the app alive.

The behaviour of the Todoist App: First you have to activate the "change app icon dynamically"-feature which closes the app. Then after starting the app again the feature is available and you can change the app icon as you want.

As far as I know Instagrams implementation didn't even need this little restart, but I would be okay with that because this solution would be better than the one existing right now.

So how does the Todoist or Instagram approach work and how would an implementation look like?

Consubstantial answered 29/7, 2021 at 12:33 Comment(14)
AFAICT, Todoist is using that same basic technique. They've got about 30 different <activity-alias> entries in their current manifest. I'm not yet sure how to explain the activation sequence, though. Indeed, after the first activation and restart, it never asks to do that again, which makes one wonder why it's not just set up like that from the start.Woodie
Yes this was also really weird to me. So the killing of the App seems to be necessary one time but then the question is why it is not necessary anymore for the next changes and what they have done to prevent the killing then.Consubstantial
In poking around their code, my first thought is that perhaps there is some subtle difference in behavior when using setComponentEnabledSetting() with COMPONENT_ENABLED_STATE_DISABLED versus COMPONENT_ENABLED_STATE_DEFAULT, as they only use COMPONENT_ENABLED_STATE_DISABLED with the default <activity-alias>, HomeActivityDefault; i.e., the only one that doesn't have android:enabled="false" set. The rest of them are set to COMPONENT_ENABLED_STATE_DEFAULT. Also, one of those other <activity-alias> entries – HomeActivityTodoist – is the same as the default, so maybe after...Woodie
...the initial DISABLED setting on the default alias, the rest of the changes are just ENABLED or DEFAULT between the rest of the <activity-alias>es, which might not force a restart. That's all purely conjecture at this point, as I can't test anything atm.Woodie
Wow didn't expect to get a solution from you this quick. Thank you so much for testing this out and giving me/us a good example on how to implement such behaviour. Besides this will be a workaround for now as android isn't officially supporting this feature yet, do you know about the drawbacks of this implementation? I read about loosing the ability to update the app when a different alias is activated. Will this really not work? And if yes is there any other workaround as switching the icon/activity-alias back before the update?Consubstantial
No problem. I just happened to be setting up a new dev machine while I was investigating this, so I used the opportunity to test the Git/GitHub setup. Sorry the code's kind of a mess; it was late. Anyhoo, as far as I'm aware, the only main issue to upgrading is that you can't ever change the class names for your aliases, or remove any of them altogether. Apart from that, I think it's basically just the occasional issue with launching; e.g., the user's launcher isn't going to update immediately so they might get "App not installed" until it does, the launcher icons might simply be removed...Woodie
...instead of updated, also Android Studio will try to launch the wrong thing if you're updating a debug install that has a new alias set, etc. You should always be able to launch it from the app drawer, or whatever the main app list is in your launcher. I'm not 100% certain of all that, though; I've never released an app with this functionality. I did include a reset button in the demo, however, to at least show how that could work, and to make it a little easier during testing and debugging (provided that you can remember to reset before pushing a build that requires a fresh install :-).Woodie
Alright so all this has to be tested out on a production app with updates. I will post here again when I tried it out and tell about my observations. But don't expect that to be in the near future because I never released any app before :D Thanks for all your efforts! Hopefully someday android will make it easier for us - just like iOSConsubstantial
yes no problem :)Consubstantial
I finally cleaned up that demo a bit, so I'll leave the link again, in case it might be of help to others: github.com/gonodono/app-icon-change-demo. Cheers!Woodie
thanks for that extra work. really appreciate it :)Consubstantial
@MikeM. that was good observation about COMPONENT_ENABLED_STATE_DEFAULTArteaga
Also i found this for Google Calendar app: codeproject.com/Articles/5269715/… Launchers do treat them specially. I tried installing GoogleCalendar app on phone with PlayServices and without: right after installation app icon was showing the day of month. Then i disabled custom MicrosoftLauncher and custom app icon was goneArteaga
For instagram case, it was Shortcut on android, not app icon itself: youtube.com/watch?v=tzWdVyQP1oEArteaga
B
0

Thanks to Mike M.

I found a workaround to change the icon without closing the app. All you need is to create another config activity and set main activity's launch mode to single instance. (Main activity and its alias should be disabled)

<activity
        android:name=".config.ConfigActivity"
        android:exported="true"
        android:enabled="true"
        android:icon="@mipmap/ic_light"
        android:screenOrientation="sensorPortrait"
        tools:ignore="DiscouragedApi,LockedOrientationActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity
        android:name=".MainActivity"
        android:exported="true"
        android:enabled="false"
        android:icon="@mipmap/ic_light_round"
        android:launchMode="singleInstance"
        android:screenOrientation="sensorPortrait"
        tools:ignore="DiscouragedApi,LockedOrientationActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <activity-alias
        android:name=".MainActivityDark"
        android:exported="true"
        android:enabled="false"
        android:icon="@mipmap/ic_dark_round"
        android:targetActivity=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity-alias>

After this you have to do some manipulations:

· Enable main activity in onCreate() and start it with some extra - Boolean:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    this.enableMainActivity()
    startActivity(
        Intent(this, MainActivity::class.java).apply {
            putExtra("is_config", true)
        }
    )
}

· Disable config activity in onCreate():

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    val isConfigNeeded = intent.getBooleanExtra("is_config", false)
    if (isConfigNeeded) {
        disableConfigActivity()
    }

    // UI
}

The only one step is ahead:

· Start main activity in config activity's onDestroy():

override fun onDestroy() {
    super.onDestroy()
    startActivity(Intent(this, MainActivity::class.java))
}

You can change the icon now by enabling/defaulting.

Thank you for the attention! Github repo: xo-tymoshenko/iconchange

Buskirk answered 3/11 at 13:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.