USB Permissions without prompt - android

I have 2 activities within my app. Say FirstActivity and SecondActivity. FirstActivity is the MAIN and LAUNCHER activity. SecondActivity uses usb devices. I want the prompt for USB permission to appear only once within lifetime of the app.
If there was only one Activity, the following lines in manifest solved my purpose:
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="#xml/usb_device_filter" />
</activity>
This was doing the following:
Launching FirstActivity whenever usb device (mentioned in xml) is connected is app is not already open.
Prompt for usb device permission appears only once.
How do I modify this to achieve the following:
If SecondActivity is already running and a new usb device is attached, I must be able to use the device without relaunching the app. So I have written a broadcast receiver for the same as follows:
public class TriggerReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
read connected usb devices and register serial port call listener back.
}
}
But the problem is FirstActivity gets relaunched again when usb device is attached while SecondActivity is running. How do I avoid this ?
Will add more information if needed. Would be thankful for any help.

Try "remove" intent filter <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> from FirstActivity like in this question
Update
FirstActivity triggers on every USB_DEVICE_ATTACHED (even SecondActivity is running) because You set <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> filter for it in AndroidManifest.xml file. So You should disable this filter when SecondActivity running. You can do this by that way:
1) add (e.g. AliasFirstActivity) in AndroidManifest.xml to your FirstActivity and move <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> filter to alias description (You should remove <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />from FirstActivity description) like that:
<activity-alias
android:targetActivity=".FirstActivity"
android:name=".AliasFirstActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="#xml/device_filter" />
</activity-alias>
2) add this code to onCreate() (or to onResume()) of SecondActivity
PackageManager pm = getApplicationContext().getPackageManager();
ComponentName compName =
new ComponentName(getPackageName(), getPackageName() + ".AliasFirstActivity");
pm.setComponentEnabledSetting(
compName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
to suppress intent filter USB_DEVICE_ATTACHED for FirstActivity. You should have in SecondActivity something like that:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
triggerReceiver = new TriggerReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(triggerReceiver, filter);
PackageManager pm = getApplicationContext().getPackageManager();
ComponentName compName =
new ComponentName(getPackageName(), getPackageName() + ".AliasFirstActivity");
pm.setComponentEnabledSetting(
compName,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
That should solve Your issue.
3) if it is needed, You can restore <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" /> filter for FirstActivity in onDestroy() (or in onPause()) of SecondActivity by using this code:
PackageManager pm = getApplicationContext().getPackageManager();
ComponentName compName =
new ComponentName(getPackageName(), getPackageName() + ".AliasFirstActivity");
pm.setComponentEnabledSetting(
compName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);

But the problem is FirstActivity gets relaunched again when usb device is attached while SecondActivity is running. How do I avoid this?
This is not hard to answer. In your AndroidManifest.xml you literally declare that your FirstActivity should be launched when the event android.hardware.usb.action.USB_DEVICE_ATTACHED occurs.
If you want to handle this event in SecondActivity only, then you have to declare it in the manifest accordingly, for example:
<activity android:name=".FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SecondActivity" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="#xml/device_filter" />
</activity>
Now, whenever your USB device is plugged in, SecondActivity will be launched only. If SecondActivity is already running, then it won't be launched again (or multiple times) because of the attribute android:launchMode="singleTask" specified for SecondActivity. You can read more about the different launch modes here if you're interested.
Since you declared in your manifest that SecondActivity should be launched when a USB device is plugged in, the Android system will ask you the following question:
After ticking the checkbox "Use by default for this USB device", it won't ask you again. Now, everytime you plug in the USB device, your SecondActivity will be launched and it will automatically receive the required USB permissions too.
Let me know if that answers your question.

This answer might be helpful:
USB device access pop-up suppression?
Code snippet:
public class UsbEventReceiverActivity extends Activity
{
public static final String ACTION_USB_DEVICE_ATTACHED = "com.example.ACTION_USB_DEVICE_ATTACHED";
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
}
#Override
protected void onResume()
{
super.onResume();
Intent intent = getIntent();
if (intent != null)
{
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED))
{
Parcelable usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
// Create a new intent and put the usb device in as an extra
Intent broadcastIntent = new Intent(ACTION_USB_DEVICE_ATTACHED);
broadcastIntent.putExtra(UsbManager.EXTRA_DEVICE, usbDevice);
// Broadcast this event so we can receive it
sendBroadcast(broadcastIntent);
}
}
// Close the activity
finish();
}
}

Related

Activate Splash Activity or Main Activity based on the status of app

I want to open a specific file from another app with my app to handle it. For example, open a attached file in a mail from Gmail app.
With the following intent-filter setting, it works fine. When I open a file, MainActivity shows up and handles it irrespective of whether it is opened through another app or directly from my app. But I want the flow starting from SplashScreen Activity, in the event that the file is opened from another app. On the other hand, if app has been activated, activate directly MainActivity.
Does anyone know how to fix it??
AndroidManifest.xml
<activity android:name=".SplashScreenActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:mimeType="*/*"
android:scheme="content" />
</intent-filter>
</activity>
You have to replace your activity from
to
<activity android:name=".SplashActivity">
And in SplashActivity get Action from Intent and then check if the Action is android.intent.action.VIEW Then Open your MainActivity and send your file from SplashActivity to MainActivity.
That's it
You can't change launcher activity from manifest file. You can set more than one <category android:name="android.intent.category.LAUNCHER"/> in intent-filter but You have to set a default activity.
But there is a way you can solve your problem...
Make a launcher activity with No UI and open the activity with condition in onCreate method.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent;
if (condition) {
intent = new Intent(this, ClassA.class);
} else {
intent = new Intent(this, ClassB.class);
}
startActivity(intent);
finish();
}
OR
In your splash activity write condition before setContentView method.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent;
if (condition) {
setContentView();
} else {
intent = new Intent(this, ClassB.class);
startActivity(intent);
finish();
}
}
Hope this will help you.

How to change android app icon based on date of the month [duplicate]

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);

BroadcastReceiver monitoring for a specific USB device attached

I have an activity that starts when a specific USB device is attached, as specified in a device filter file, which works great:
<activity
android:name="com.mycompany.DerpApp.MainActivity"
android:launchMode="singleTask"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="#xml/device_filter" />
</activity>
I also have a service where I want to monitor for connect and disconnect. I have BroadcastReceivers wired up, and they fire upon device attach and detach. However, I want these broadcast receivers to trigger when only a device as specified in my device_filter.xml is attached/detached.
m_usbDisconnectReceiver = new UsbDisconnectReceiver();
registerReceiver(m_usbDisconnectReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED));
m_usbConnectReceiver = new UsbConnectReceiver();
registerReceiver(m_usbConnectReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED));
I am unsure of how to attach my device_filter file to the programatically created Broadcast Receiver. Is there something I can do in the IntentFilter for this? I think that the Intent that is provided to the onReceive() has a UsbDevice as one of its extras, but it would be best if I could filter it out so the event doesn't fire. And if that's not possible, how can I check to see if the UsbDevice is a part of my device_filter?
If you absolutely have to create your BroadcastReceiver programatically, then you need to filter the devices programatically as well.
Try this:
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED))
{
UsbDevice d = (UsbDevice)
intent.getExtras().get(UsbManager.EXTRA_DEVICE);
if (d.getVendorId() == MY_VENDOR_ID && d.getDeviceId() == MY_DEVICE_ID)
{
// Your code here
}
}
}

How do i dynamically choose which activity to launch when opening an app

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.

How to change an application icon programmatically in Android?

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);

Categories

Resources