Related
I use activity-alias to dynamically change the icon of my application, resulting in my application disappear in the recent apps.
Manifest
<activity-alias
android:enabled="false"
android:icon="#mipmap/ic_launcher_11"
android:label="#string/app_name"
android:name=".ui.launcher_d_eleven"
android:targetActivity=".ui.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
private void enableComponent(PackageManager pm, String launcher) {
ComponentName newComponent = new ComponentName(this, launcher);
pm.setComponentEnabledSetting(newComponent,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
private void disableComponent(PackageManager pm, String launcherAlias) {
LoggerUtil.e("zkx disable Launcher = " + launcherAlias);
ComponentName deComponent = new ComponentName(this, launcherAlias);
pm.setComponentEnabledSetting(deComponent,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
}
Hitting it a bit late but I got a solution for this, you need to add a default alias pointing to the MainActivity without changing the icon and remove the Launcher property in the Main Activity's intent-filter manifest.
So your MainActivity would look like this
<activity
android:name=".MainActivity"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
And add a default alias that looks like this
<activity-alias
android:name=".Default"
targetActivity = ".MainActivity"
enabled = true>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
And then when you don't enable/disable your MainActivity, you disable the alias and substitute it with another alias
That's what worked for me
Is it possible to change an application icon directly from the program?
I mean, change icon.png in the res\drawable folder.
I would like to let users to change application's icon from the program so next time they would see the previously selected icon in the launcher.
Try this, it works fine for me:
1 . Modify your MainActivity section in AndroidManifest.xml, delete from it, line with MAIN category in intent-filter section
<activity android:name="ru.quickmessage.pa.MainActivity"
android:configChanges="keyboardHidden|orientation"
android:screenOrientation="portrait"
android:label="#string/app_name"
android:theme="#style/CustomTheme"
android:launchMode="singleTask">
<intent-filter>
==> <action android:name="android.intent.action.MAIN" /> <== Delete this line
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
2 . Create <activity-alias>, for each of your icons. Like this
<activity-alias android:label="#string/app_name"
android:icon="#drawable/icon"
android:name=".MainActivity-Red"
android:enabled="false"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
3 . Set programmatically: set ENABLE attribute for the appropriate activity-alias
getPackageManager().setComponentEnabledSetting(
new ComponentName("ru.quickmessage.pa", "ru.quickmessage.pa.MainActivity-Red"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Note, At least one must be enabled at all times.
It's an old question, but still active as there is no explicit Android feature. And the guys from facebook found a work around - somehow. Today, I found a way that works for me. Not perfect (see remarks at the end of this answer) but it works!
Main idea is, that I update the icon of my app's shortcut, created by the launcher on my home screen. When I want to change something on the shortcut-icon, I remove it first and recreate it with a new bitmap.
Here is the code. It has a button increment. When pressed, the shortcut is replaced with one that has a new counting number.
First you need these two permissions in your manifest:
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
Then you need this two methods for installing and uninstalling shortcuts. The shortcutAdd method creates a bitmap with a number in it. This is just to demonstrate that it actually changes. You probably want to change that part with something, you want in your app.
private void shortcutAdd(String name, int number) {
// Intent to be send, when shortcut is pressed by user ("launched")
Intent shortcutIntent = new Intent(getApplicationContext(), Play.class);
shortcutIntent.setAction(Constants.ACTION_PLAY);
// Create bitmap with number in it -> very default. You probably want to give it a more stylish look
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Paint paint = new Paint();
paint.setColor(0xFF808080); // gray
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(50);
new Canvas(bitmap).drawText(""+number, 50, 50, paint);
((ImageView) findViewById(R.id.icon)).setImageBitmap(bitmap);
// Decorate the shortcut
Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
// Inform launcher to create shortcut
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(addIntent);
}
private void shortcutDel(String name) {
// Intent to be send, when shortcut is pressed by user ("launched")
Intent shortcutIntent = new Intent(getApplicationContext(), Play.class);
shortcutIntent.setAction(Constants.ACTION_PLAY);
// Decorate the shortcut
Intent delIntent = new Intent();
delIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
delIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
// Inform launcher to remove shortcut
delIntent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(delIntent);
}
And finally, here are two listener to add the first shortcut and update the shortcut with an incrementing counter.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
findViewById(R.id.add).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
shortcutAdd("changeIt!", count);
}
});
findViewById(R.id.increment).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
shortcutDel("changeIt!");
count++;
shortcutAdd("changeIt!", count);
}
});
}
Remarks:
This way works also if your App controls more shortcuts on the home screen, e.g. with different extra's in the Intent. They just need different names so that the right one is uninstalled and reinstalled.
The programmatical handling of shortcuts in Android is a well known, widely used but not officially supported Android feature. It seems to work on the default launcher and I never tried it anywhere else. So dont blame me, when you get this user-emails "It does not work on my XYZ, double rooted, super blasted phone"
The launcher writes a Toast when a shortcut was installad and one when a shortcut was uninstalled. So I get two Toasts every time I change the icon. This is not perfect, but well, as long as the rest of my app is perfect...
You cannot change the manifest or the resource in the signed-and-sealed APK, except through a software upgrade.
Programatically, you may want to publish the application launcher yourself :
Note: this method no longer works starting with Android 8.0 - Oreo
In your AndroidManifest.xml, add :
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
Then you need create your app launcher intent:
Intent myLauncherIntent = new Intent();
myLauncherIntent.setClassName("your.package.name", "YourLauncherActivityName");
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Create an install shortcut intent with your app launcher and custom icon:
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, myLauncherIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Application Name");
intent.putExtra
(
Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext
(
getApplicationContext(),
R.drawable.app_icon
)
);
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
And finally launch the broadcast intent:
getApplicationContext().sendBroadcast(intent);
Assuming you mean changing the icon shown on the home screen, this could easily be done by creating a widget that does exactly this. Here's an article that demonstrate how that can be accomplished for a "new messages" type application similar to iPhone:
http://www.cnet.com/8301-19736_1-10278814-251.html
#P-A's solution partially works for me. Detail my findings below:
1) The first code snippet is incorrect, see below:
<activity
...
<intent-filter>
==> <action android:name="android.intent.action.MAIN" /> <== This line shouldn't be deleted, otherwise will have compile error
<category android:name="android.intent.category.LAUNCHER" /> //DELETE THIS LINE
</intent-filter>
</activity>
2) Should use following code to disable all icons before enabling another one, otherwise it will add a new icon, instead of replacing it.
getPackageManager().setComponentEnabledSetting(
getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
BUT, if you use code above, then shortcut on homescreen will be removed! And it won't be automatically added back. You might be able to programmatically add icon back, but it probably won't stay in the same position as before.
3) Note that the icon won't get changed immediately, it might take several seconds. If you click it right after changing, you might get an error saying: "App isn't installed".
So, IMHO this solution is only suitable for changing icon in app launcher only, not for shortcuts (i.e. the icon on homescreen)
As mentioned before you need use <activity-alias> to change the application icon.
To avoid killing the application after enabling appropriate activity-alias you need to do this after the application is killed. To find out if the application was killed you can use this method
Create activity aliases in AndroidManifest.xml
<activity android:name=".ui.MainActivity"/>
<activity-alias
android:name=".one"
android:icon="#mipmap/ic_launcher_one"
android:targetActivity=".ui.MainActivity"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".two"
android:icon="#mipmap/ic_launcher_two"
android:targetActivity=".ui.MainActivity"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
Сreate a service that will change the active activity-alias after killing the application. You need store the name of new active activity-alias somewhere (e.g. SharedPreferences)
class ChangeAppIconService: Service() {
private val aliases = arrayOf(".one", ".two")
override fun onBind(intent: Intent?): IBinder? = null
override fun onTaskRemoved(rootIntent: Intent?) {
changeAppIcon()
stopSelf()
}
fun changeAppIcon() {
val sp = getSharedPreferences("appSettings", Context.MODE_PRIVATE)
sp.getString("activeActivityAlias", ".one").let { aliasName ->
if (!isAliasEnabled(aliasName)) {
setAliasEnabled(aliasName)
}
}
}
private fun isAliasEnabled(aliasName: String): Boolean {
return packageManager.getComponentEnabledSetting(
ComponentName(
this,
"${BuildConfig.APPLICATION_ID}$aliasName"
)
) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
}
private fun setAliasEnabled(aliasName: String) {
aliases.forEach {
val action = if (it == aliasName)
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
else
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
packageManager.setComponentEnabledSetting(
ComponentName(
this,
"${BuildConfig.APPLICATION_ID}$aliasName"
),
action,
PackageManager.DONT_KILL_APP
)
}
}
}
Add service to AndroidManifest.xml
<service
android:name=".ChangeAppIconService"
android:stopWithTask="false"
/>
Start ChangeAppIconService in MainActivity.onCreate
class MainActivity: Activity {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
startService(Intent(this, ChangeAppIconService::class.java))
...
}
...
}
Try this solution
<activity android:name=".SplashActivity"
android:label="#string/app_name"
android:icon="#drawable/ic_launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity-alias android:label="ShortCut"
android:icon="#drawable/ic_short_cut"
android:name=".SplashActivityAlias"
android:enabled="false"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
Add the following code when you want to change your app icon
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName(YourActivity.this,
"your_package_name.SplashActivity"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(
new ComponentName(YourActivity.this,
"your_package_name.SplashActivityAlias"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
AndroidManifest.xml example:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name="com.pritesh.resourceidentifierexample.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<!--<category android:name="android.intent.category.LAUNCHER"/>-->
</intent-filter>
</activity>
<activity-alias android:label="RED"
android:icon="#drawable/ic_android_red"
android:name="com.pritesh.resourceidentifierexample.MainActivity-Red"
android:enabled="true"
android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias android:label="GREEN"
android:icon="#drawable/ic_android_green"
android:name="com.pritesh.resourceidentifierexample.MainActivity-Green"
android:enabled="false"
android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias android:label="BLUE"
android:icon="#drawable/ic_android_blue"
android:name="com.pritesh.resourceidentifierexample.MainActivity-Blue"
android:enabled="false"
android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
Then follow below given code in MainActivity:
ImageView imageView = (ImageView)findViewById(R.id.imageView);
int imageResourceId;
String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
int hours = new Time(System.currentTimeMillis()).getHours();
Log.d("DATE", "onCreate: " + hours);
getPackageManager().setComponentEnabledSetting(
getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
if(hours == 13)
{
imageResourceId = this.getResources().getIdentifier("ic_android_red", "drawable", this.getPackageName());
getPackageManager().setComponentEnabledSetting(
new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Red"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}else if(hours == 14)
{
imageResourceId = this.getResources().getIdentifier("ic_android_green", "drawable", this.getPackageName());
getPackageManager().setComponentEnabledSetting(
new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Green"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}else
{
imageResourceId = this.getResources().getIdentifier("ic_android_blue", "drawable", this.getPackageName());
getPackageManager().setComponentEnabledSetting(
new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Blue"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
imageView.setImageResource(imageResourceId);
Applying the suggestions mentioned, I've faced the issue of app getting killed whenever default icon gets changed to new icon. So have implemented the code with some tweaks.
Step 1). In file AndroidManifest.xml, create for default activity with android:enabled="true" & other alias with android:enabled="false". Your will not contain but append those in with android:enabled="true".
<activity
android:name=".activities.SplashActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/SplashTheme">
</activity>
<!-- <activity-alias used to change app icon dynamically> : default icon, set enabled true -->
<activity-alias
android:label="#string/app_name"
android:icon="#mipmap/ic_launcher"
android:roundIcon="#mipmap/ic_launcher_round"
android:name=".SplashActivityAlias1" <!--put any random name started with dot-->
android:enabled="true"
android:targetActivity=".activities.SplashActivity"> <!--target activity class path will be same for all alias-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<!-- <activity-alias used to change app icon dynamically> : sale icon, set enabled false initially -->
<activity-alias
android:label="#string/app_name"
android:icon="#drawable/ic_store_marker"
android:roundIcon="#drawable/ic_store_marker"
android:name=".SplashActivityAlias" <!--put any random name started with dot-->
android:enabled="false"
android:targetActivity=".activities.SplashActivity"> <!--target activity class path will be same for all alias-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
Step 2). Make a method that will be used to disable 1st activity-alias that contains default icon & enable 2nd alias that contains icon need to be changed.
/**
* method to change the app icon dynamically
*
* #param context
* #param isNewIcon : true if new icon need to be set; false to set default
* icon
*/
public static void changeAppIconDynamically(Context context, boolean isNewIcon) {
PackageManager pm = context.getApplicationContext().getPackageManager();
if (isNewIcon) {
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias1"), //com.example.dummy will be your package
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
} else {
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias1"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
Step 3). Now call this method depending on your requirement, say on button click or date specific or occasion specific conditions, simply like -
// Switch app icon to new icon
GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, true);
// Switch app icon to default icon
GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, false);
Hope this will help those who face the issue of app getting killed on icon change.
Happy Coding :)
To get the solution by Markus working I needed the first Intent so be:
Intent myLauncherIntent = new Intent(Intent.ACTION_MAIN);
myLauncherIntent.setClassName(this, this.getClass().getName());
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
I would like to hide my android app from the launcher, but be able to call it from within another app. I am lost on what to remove from the android manifest.
Already tried removing...
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
...but then it doesn't open when called from another app.
Here is what how I am calling this hidden
Intent i;
PackageManager manager = getPackageManager();
try {
i = manager.getLaunchIntentForPackage("org.xbmc.xbmc");
if (i == null)
throw new PackageManager.NameNotFoundException();
i.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(i);
} catch (PackageManager.NameNotFoundException e) {
Here is the top of the manifest
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application android:label="#string/app_name" android:icon="#drawable/ic_launcher" android:hasCode="true" android:debuggable="true">
<activity android:theme="#*android:style/Theme.NoTitleBar.Fullscreen" android:name=".Splash" android:finishOnTaskLaunch="true" android:launchMode="singleInstance" android:screenOrientation="sensorLandscape" android:configChanges="touchscreen|keyboard|keyboardHidden|navigation|orientation">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
You need to remove the following line from your AndroidManifest.xml:
<category android:name="android.intent.category.LAUNCHER"/>
This will remove the application from the default launcher. However, you also need to add the following line such that your BroadcastReceiver is not completely ignored:
<category android:name="android.intent.category.DEFAULT"/>
You should NOT remove the line below - it is used to specify which Activity should launch first when your app is opened:
<action android:name="android.intent.action.MAIN"/>
EDIT
In order to launch the application discussed above from another application, you cannot use the calls shown in your question. You are trying to open the application by creating an Intent with the CATEGORY_LAUNCHER tag (i.addCategory(Intent.CATEGORY_LAUNCHER)) when you have explicitly removed the following line from your AndroidManifest.xml file:
<category android:name="android.intent.category.LAUNCHER" />
The absence of the above line means that the application you are trying to call will ignore the launch Intent. In order to launch your application you will need to act upon another Intent. Here is an example that shows how to open an application, which doesn't contain a launch intent filter, by responding to a SMS Intent: How to launch an Android app without "android.intent.category.LAUNCHER"
Which intent you choose to use is up to you - just make sure you add it to your AndroidManifest.xml file.
Try this code:
PackageManager p = getPackageManager();
p.setComponentEnabledSetting(getComponentName(),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
and check this link.
hope this helps.
I am writing an app that requires you to be logged in to a service before using it. From my understanding of android so far, you have to choose which activity to launch when you open from the launcher in the manifest. I don't know which activity i want to launch at compile time. I want the user to click the icon, then I check and see if they're logged in, then decide based on that whether to launch the login activity, or the main app activity. Is there a way to do this?
No, since you have to run some code, there's no way to declaratively (in manifest) to say this. You have to launch an activity (set in manifest), then have this activity decide based on if the user is logged on or not what second activity to launch via Intent:
final Class<? extends Activity> activityClass;
if(userIsLoggedOn())
activityClass = LoggedOnActivity.class;
else
activityClass = LogInActivity.class;
Intent newActivity = new Intent(context, activityClass);
context.startActivity(newActivity);
There is another way to do that using activity-alias.
In the Manifest :
<activity
android:name=".LoginActivity"
android:icon="#drawable/ic_launcher_main"
android:label="Login" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".MainActivity"
android:icon="#drawable/ic_launcher_main"
android:label="MainActivity" >
</activity>
<activity-alias
android:name=".AliasActivity"
android:label="AliasActivity"
android:enabled="false"
android:targetActivity=".MainActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
2.Somewhere in the Login Activity:
String s = getApplicationContext().getPackageName();
ComponentName cm = new ComponentName(s, s+".AliasActivity");
ComponentName cm2 = new ComponentName(s, s+".Login");
PackageManager pm = this.getPackageManager();
pm.setComponentEnabledSetting(cm, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 1);
pm.setComponentEnabledSetting(cm2, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
after that, the app will be killed once and next time you launch app, the MainActivity would be the launcher.
The Android Framewowrk provides the method
public Intent setClassName (String packageName, String className)
of the Intent class that you can use to dynamically choose which activity to invoke with just the name of the class in String.
Here's an example
String packageName = getPackageName(), className=packageName+"subFolder.myActivity";
Intent i = new Intent();
i.setClassName(packageName, className);
startActivity(i);
https://developer.android.com/reference/android/content/Intent.html#setClassName(java.lang.String,%20java.lang.String)
Just as above #auval said, I test the code as below and it do well!
At first ,the AndroidManifest.xml file is look like this:
<activity
android:name=".LauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".MainActivity">
</activity>
<activity-alias
android:name=".AliasActivity"
android:enabled="false"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
Second,you can put these code in somewhere in the MainActivity.class:
private void changeLauncher() {
String s = getApplicationContext().getPackageName();
ComponentName cm = new ComponentName(s, s + ".AliasActivity");
ComponentName cm2 = new ComponentName(s, s + ".LauncherActivity");
PackageManager pm = this.getPackageManager();
pm.setComponentEnabledSetting(cm,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP );
pm.setComponentEnabledSetting(cm2,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
Now,when you first launch the app ,the LauncherActivity would be launched and when you exit the app ,run the app again,the MainActivity would be launched.
Is it possible to change an application icon directly from the program?
I mean, change icon.png in the res\drawable folder.
I would like to let users to change application's icon from the program so next time they would see the previously selected icon in the launcher.
Try this, it works fine for me:
1 . Modify your MainActivity section in AndroidManifest.xml, delete from it, line with MAIN category in intent-filter section
<activity android:name="ru.quickmessage.pa.MainActivity"
android:configChanges="keyboardHidden|orientation"
android:screenOrientation="portrait"
android:label="#string/app_name"
android:theme="#style/CustomTheme"
android:launchMode="singleTask">
<intent-filter>
==> <action android:name="android.intent.action.MAIN" /> <== Delete this line
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
2 . Create <activity-alias>, for each of your icons. Like this
<activity-alias android:label="#string/app_name"
android:icon="#drawable/icon"
android:name=".MainActivity-Red"
android:enabled="false"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
3 . Set programmatically: set ENABLE attribute for the appropriate activity-alias
getPackageManager().setComponentEnabledSetting(
new ComponentName("ru.quickmessage.pa", "ru.quickmessage.pa.MainActivity-Red"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
Note, At least one must be enabled at all times.
It's an old question, but still active as there is no explicit Android feature. And the guys from facebook found a work around - somehow. Today, I found a way that works for me. Not perfect (see remarks at the end of this answer) but it works!
Main idea is, that I update the icon of my app's shortcut, created by the launcher on my home screen. When I want to change something on the shortcut-icon, I remove it first and recreate it with a new bitmap.
Here is the code. It has a button increment. When pressed, the shortcut is replaced with one that has a new counting number.
First you need these two permissions in your manifest:
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
Then you need this two methods for installing and uninstalling shortcuts. The shortcutAdd method creates a bitmap with a number in it. This is just to demonstrate that it actually changes. You probably want to change that part with something, you want in your app.
private void shortcutAdd(String name, int number) {
// Intent to be send, when shortcut is pressed by user ("launched")
Intent shortcutIntent = new Intent(getApplicationContext(), Play.class);
shortcutIntent.setAction(Constants.ACTION_PLAY);
// Create bitmap with number in it -> very default. You probably want to give it a more stylish look
Bitmap bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888);
Paint paint = new Paint();
paint.setColor(0xFF808080); // gray
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(50);
new Canvas(bitmap).drawText(""+number, 50, 50, paint);
((ImageView) findViewById(R.id.icon)).setImageBitmap(bitmap);
// Decorate the shortcut
Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
// Inform launcher to create shortcut
addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(addIntent);
}
private void shortcutDel(String name) {
// Intent to be send, when shortcut is pressed by user ("launched")
Intent shortcutIntent = new Intent(getApplicationContext(), Play.class);
shortcutIntent.setAction(Constants.ACTION_PLAY);
// Decorate the shortcut
Intent delIntent = new Intent();
delIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
delIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
// Inform launcher to remove shortcut
delIntent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(delIntent);
}
And finally, here are two listener to add the first shortcut and update the shortcut with an incrementing counter.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test);
findViewById(R.id.add).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
shortcutAdd("changeIt!", count);
}
});
findViewById(R.id.increment).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
shortcutDel("changeIt!");
count++;
shortcutAdd("changeIt!", count);
}
});
}
Remarks:
This way works also if your App controls more shortcuts on the home screen, e.g. with different extra's in the Intent. They just need different names so that the right one is uninstalled and reinstalled.
The programmatical handling of shortcuts in Android is a well known, widely used but not officially supported Android feature. It seems to work on the default launcher and I never tried it anywhere else. So dont blame me, when you get this user-emails "It does not work on my XYZ, double rooted, super blasted phone"
The launcher writes a Toast when a shortcut was installad and one when a shortcut was uninstalled. So I get two Toasts every time I change the icon. This is not perfect, but well, as long as the rest of my app is perfect...
You cannot change the manifest or the resource in the signed-and-sealed APK, except through a software upgrade.
Programatically, you may want to publish the application launcher yourself :
Note: this method no longer works starting with Android 8.0 - Oreo
In your AndroidManifest.xml, add :
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
Then you need create your app launcher intent:
Intent myLauncherIntent = new Intent();
myLauncherIntent.setClassName("your.package.name", "YourLauncherActivityName");
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Create an install shortcut intent with your app launcher and custom icon:
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, myLauncherIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Application Name");
intent.putExtra
(
Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext
(
getApplicationContext(),
R.drawable.app_icon
)
);
intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
And finally launch the broadcast intent:
getApplicationContext().sendBroadcast(intent);
Assuming you mean changing the icon shown on the home screen, this could easily be done by creating a widget that does exactly this. Here's an article that demonstrate how that can be accomplished for a "new messages" type application similar to iPhone:
http://www.cnet.com/8301-19736_1-10278814-251.html
#P-A's solution partially works for me. Detail my findings below:
1) The first code snippet is incorrect, see below:
<activity
...
<intent-filter>
==> <action android:name="android.intent.action.MAIN" /> <== This line shouldn't be deleted, otherwise will have compile error
<category android:name="android.intent.category.LAUNCHER" /> //DELETE THIS LINE
</intent-filter>
</activity>
2) Should use following code to disable all icons before enabling another one, otherwise it will add a new icon, instead of replacing it.
getPackageManager().setComponentEnabledSetting(
getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
BUT, if you use code above, then shortcut on homescreen will be removed! And it won't be automatically added back. You might be able to programmatically add icon back, but it probably won't stay in the same position as before.
3) Note that the icon won't get changed immediately, it might take several seconds. If you click it right after changing, you might get an error saying: "App isn't installed".
So, IMHO this solution is only suitable for changing icon in app launcher only, not for shortcuts (i.e. the icon on homescreen)
As mentioned before you need use <activity-alias> to change the application icon.
To avoid killing the application after enabling appropriate activity-alias you need to do this after the application is killed. To find out if the application was killed you can use this method
Create activity aliases in AndroidManifest.xml
<activity android:name=".ui.MainActivity"/>
<activity-alias
android:name=".one"
android:icon="#mipmap/ic_launcher_one"
android:targetActivity=".ui.MainActivity"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".two"
android:icon="#mipmap/ic_launcher_two"
android:targetActivity=".ui.MainActivity"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
Сreate a service that will change the active activity-alias after killing the application. You need store the name of new active activity-alias somewhere (e.g. SharedPreferences)
class ChangeAppIconService: Service() {
private val aliases = arrayOf(".one", ".two")
override fun onBind(intent: Intent?): IBinder? = null
override fun onTaskRemoved(rootIntent: Intent?) {
changeAppIcon()
stopSelf()
}
fun changeAppIcon() {
val sp = getSharedPreferences("appSettings", Context.MODE_PRIVATE)
sp.getString("activeActivityAlias", ".one").let { aliasName ->
if (!isAliasEnabled(aliasName)) {
setAliasEnabled(aliasName)
}
}
}
private fun isAliasEnabled(aliasName: String): Boolean {
return packageManager.getComponentEnabledSetting(
ComponentName(
this,
"${BuildConfig.APPLICATION_ID}$aliasName"
)
) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
}
private fun setAliasEnabled(aliasName: String) {
aliases.forEach {
val action = if (it == aliasName)
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
else
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
packageManager.setComponentEnabledSetting(
ComponentName(
this,
"${BuildConfig.APPLICATION_ID}$aliasName"
),
action,
PackageManager.DONT_KILL_APP
)
}
}
}
Add service to AndroidManifest.xml
<service
android:name=".ChangeAppIconService"
android:stopWithTask="false"
/>
Start ChangeAppIconService in MainActivity.onCreate
class MainActivity: Activity {
...
override fun onCreate(savedInstanceState: Bundle?) {
...
startService(Intent(this, ChangeAppIconService::class.java))
...
}
...
}
Try this solution
<activity android:name=".SplashActivity"
android:label="#string/app_name"
android:icon="#drawable/ic_launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity-alias android:label="ShortCut"
android:icon="#drawable/ic_short_cut"
android:name=".SplashActivityAlias"
android:enabled="false"
android:targetActivity=".SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
Add the following code when you want to change your app icon
PackageManager pm = getPackageManager();
pm.setComponentEnabledSetting(
new ComponentName(YourActivity.this,
"your_package_name.SplashActivity"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(
new ComponentName(YourActivity.this,
"your_package_name.SplashActivityAlias"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
AndroidManifest.xml example:
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name="com.pritesh.resourceidentifierexample.MainActivity"
android:label="#string/app_name"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<!--<category android:name="android.intent.category.LAUNCHER"/>-->
</intent-filter>
</activity>
<activity-alias android:label="RED"
android:icon="#drawable/ic_android_red"
android:name="com.pritesh.resourceidentifierexample.MainActivity-Red"
android:enabled="true"
android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias android:label="GREEN"
android:icon="#drawable/ic_android_green"
android:name="com.pritesh.resourceidentifierexample.MainActivity-Green"
android:enabled="false"
android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias android:label="BLUE"
android:icon="#drawable/ic_android_blue"
android:name="com.pritesh.resourceidentifierexample.MainActivity-Blue"
android:enabled="false"
android:targetActivity="com.pritesh.resourceidentifierexample.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
</application>
Then follow below given code in MainActivity:
ImageView imageView = (ImageView)findViewById(R.id.imageView);
int imageResourceId;
String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
int hours = new Time(System.currentTimeMillis()).getHours();
Log.d("DATE", "onCreate: " + hours);
getPackageManager().setComponentEnabledSetting(
getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
if(hours == 13)
{
imageResourceId = this.getResources().getIdentifier("ic_android_red", "drawable", this.getPackageName());
getPackageManager().setComponentEnabledSetting(
new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Red"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}else if(hours == 14)
{
imageResourceId = this.getResources().getIdentifier("ic_android_green", "drawable", this.getPackageName());
getPackageManager().setComponentEnabledSetting(
new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Green"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}else
{
imageResourceId = this.getResources().getIdentifier("ic_android_blue", "drawable", this.getPackageName());
getPackageManager().setComponentEnabledSetting(
new ComponentName("com.pritesh.resourceidentifierexample", "com.pritesh.resourceidentifierexample.MainActivity-Blue"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}
imageView.setImageResource(imageResourceId);
Applying the suggestions mentioned, I've faced the issue of app getting killed whenever default icon gets changed to new icon. So have implemented the code with some tweaks.
Step 1). In file AndroidManifest.xml, create for default activity with android:enabled="true" & other alias with android:enabled="false". Your will not contain but append those in with android:enabled="true".
<activity
android:name=".activities.SplashActivity"
android:label="#string/app_name"
android:screenOrientation="portrait"
android:theme="#style/SplashTheme">
</activity>
<!-- <activity-alias used to change app icon dynamically> : default icon, set enabled true -->
<activity-alias
android:label="#string/app_name"
android:icon="#mipmap/ic_launcher"
android:roundIcon="#mipmap/ic_launcher_round"
android:name=".SplashActivityAlias1" <!--put any random name started with dot-->
android:enabled="true"
android:targetActivity=".activities.SplashActivity"> <!--target activity class path will be same for all alias-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<!-- <activity-alias used to change app icon dynamically> : sale icon, set enabled false initially -->
<activity-alias
android:label="#string/app_name"
android:icon="#drawable/ic_store_marker"
android:roundIcon="#drawable/ic_store_marker"
android:name=".SplashActivityAlias" <!--put any random name started with dot-->
android:enabled="false"
android:targetActivity=".activities.SplashActivity"> <!--target activity class path will be same for all alias-->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
Step 2). Make a method that will be used to disable 1st activity-alias that contains default icon & enable 2nd alias that contains icon need to be changed.
/**
* method to change the app icon dynamically
*
* #param context
* #param isNewIcon : true if new icon need to be set; false to set default
* icon
*/
public static void changeAppIconDynamically(Context context, boolean isNewIcon) {
PackageManager pm = context.getApplicationContext().getPackageManager();
if (isNewIcon) {
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias1"), //com.example.dummy will be your package
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
} else {
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias1"),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);
pm.setComponentEnabledSetting(
new ComponentName(context,
"com.example.dummy.SplashActivityAlias"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
Step 3). Now call this method depending on your requirement, say on button click or date specific or occasion specific conditions, simply like -
// Switch app icon to new icon
GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, true);
// Switch app icon to default icon
GeneralUtils.changeAppIconDynamically(EditProfileActivity.this, false);
Hope this will help those who face the issue of app getting killed on icon change.
Happy Coding :)
To get the solution by Markus working I needed the first Intent so be:
Intent myLauncherIntent = new Intent(Intent.ACTION_MAIN);
myLauncherIntent.setClassName(this, this.getClass().getName());
myLauncherIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);