I am developing an android application in which I want to display the Push notification.
It has displayed well in most of the devices except Xiaomi phones (I am using Redmi Note 4). The problem that I found is, it is because of Autostart option provided by Xiomi which will be disabled by default and the user need to enable it manually.
But I wonder that some of the Android Apps I could see enabling this option without any user interaction Ex: WhatsApp. If I try reinstalling WhatsApp and see the Autostart option , it is enabled!
I am unable to convince our client by telling it is the feature of Xiomi like devices as he is pointing out some apps which is working fine like the example I have mentioned above.
This question has been asked by some other people
Add my app to AutoStart apps list in android programmatically
How to check AutoStart is enabled for our App in Xiaomi manufacturer mobile device Programmatically
But I could not see any answers for them and Posting here with the hope that someone will have an answer for this.
The autostart feature will get enabled automatically when you will download the app from playstore if xiaomi OS wants it as apps like amazon ,google IO etc are also not allowed to autostart ,In this case you have to go to Security permissions -> autostart -> then enable autostart from there.You cannot make the app autostart by code all you can do is you can show a dialog to enable auto start and take the user to the autostart activity but this is not a good option as you cannot check whether autostart is enabled or not.
This is done by Mi in MIUI8 for saving battery .This issue wasted my 2 days XD
You can refer to this article.
For xiaomi, oppo, vivo, etc. devices to Enable Autostart option programmatically
String manufacturer = android.os.Build.MANUFACTURER;
try {
Intent intent = new Intent();
if ("xiaomi".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"));
} else if ("oppo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity"));
} else if ("vivo".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity"));
} else if ("Letv".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity"));
} else if ("Honor".equalsIgnoreCase(manufacturer)) {
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity"));
}
List<ResolveInfo> list = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) {
startActivity(intent);
}
} catch (Exception e) {
e.printStackTrace();
}
Few popular apps run in background without being killed during memory cleanup cycle (many of the popular OEMs customize the stock ROM for battery/memory optimization), because they are "White listed" by these manufactures.
For your app you can whitelist it either manually (via corresponding "settings" for the devices) or programmatically by redirecting users to the corresponding settings page to white list the app. programmatically you can do like below:
Add below permissions in the App's manifest file:`
<uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE"/>
<uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT"/>`
Redirect your to the Auto Start setting:
if (Build.BRAND.equalsIgnoreCase("xiaomi")) {
Intent intent = new Intent();
intent.setComponent(new
ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
startActivity(intent);
} else if (Build.MANUFACTURER.equalsIgnoreCase("oppo")) {
try {
Intent intent = new Intent();
intent.setClassName("com.coloros.safecenter",
"com.coloros.safecenter.permission.startup.StartupAppListActivity");
startActivity(intent);
} catch (Exception e) {
try {
Intent intent = new Intent();
intent.setClassName("com.oppo.safe",
"com.oppo.safe.permission.startup.StartupAppListActivity");
startActivity(intent);
} catch (Exception ex) {
try {
Intent intent = new Intent();
intent.setClassName("com.coloros.safecenter",
"com.coloros.safecenter.startupapp.StartupAppListActivity");
startActivity(intent);
} catch (Exception exx) {
}
}
}
}
AutoStart Reference For other OEMs
I have tested this method and it worked but the reliability is still a question as system taking time (approx 2 Min on PoccoF1 & Xiaomi devices) to restart the killed service.
But as an user we can prevent the app's background services to get killed all together as below :
Press Recent apps physical key (left side button).
Drag down the app once (select, hold & slide it down) tap on the lock icon (if the lock is in open state) to lock the app.
The app will be put in lock condition (even if you clear the background app processes by clearing, the app will keep on running).
Same way, if you want to remove it from the lock condition, just drag down again once and the lock symbol will disappear (clearing the background process will clear the app from running too).
But, With this way App's locking status will be reset on reboot on most of the devices.
EDIT:
After observing the behavior (on Xiaomi's RedmiS3, Android V6.0) of Foreground service here is the analysis:
Even after enabling the "AutoStart" programatically (via user intervention, as explained above) the service didn't restarts always (Service restarted only on few occasions, but most of the time it didn't).
Also, if I search for "AutoStart" in device settings I can't see my app there in the AutoStart list. It seems above method only providing Autostart permission but not enabling it, NOT SURE!.
And, if I add my app into "AutoStart" list via device setting, my service gets restarted (though it takes some time).
Restarting the killed service in onTaskRemoved() callback could be another option but this callback gets called in surprising way when service gets killed. This callback gets executed only when app is been closed properly by back key press. If we minimized the app (Pause state) this callback never gets called on service kill. (Looking for the reason)
Recently I found another way, the killed service could be restarted via GCM notification event. I doubt that weather the GCM works when App's gets killed on the devices or not (I need to check this and verify the behavior). But one this is for sure "These OEMs has made the programmer life hell!).
I know it is too late to share the answer but I will put my two cents here because it is very very important. I wasted my 2 days in digging this problem out. I tried all the suggested solutions as provided here but nothings seemed to be working. Below is the solution I implemented in following steps:
Step # 01
Create your foreground service as you are doing and register it accordingly in manifest. For sample purposes, I am sharing sample of service.
class MyService : Service() {
private var wakeLock: PowerManager.WakeLock? = null
override fun onBind(intent: Intent): IBinder? {
Log.d(tag!!, "Some component want to bind with the service")
// We don't provide binding, so return null
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d(tag!!, "onStartCommand executed with startId: $startId")
// by returning this we make sure the service is restarted if the system kills the service
return START_STICKY
}
override fun onCreate() {
super.onCreate()
Log.d(tag!!, "The service has been created".toUpperCase(Locale.ROOT))
startForeground(1, NotificationUtils.createNotification(this))
acquireLock()
}
override fun onDestroy() {
super.onDestroy()
Log.d(tag!!, "The service has been destroyed".toUpperCase(Locale.ROOT))
Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show()
}
override fun onTaskRemoved(rootIntent: Intent?) {
Log.d(tag!!, "onTaskRemoved")
val restartServiceIntent = Intent(applicationContext, this.javaClass)
restartServiceIntent.setPackage(packageName)
val restartServicePendingIntent = PendingIntent.getService(applicationContext, 1, restartServiceIntent, PendingIntent.FLAG_ONE_SHOT)
val alarmService = applicationContext.getSystemService(ALARM_SERVICE) as AlarmManager
alarmService[AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime() + 1000] = restartServicePendingIntent
super.onTaskRemoved(rootIntent)
}
#SuppressLint("WakelockTimeout")
private fun acquireLock() {
// we need this lock so our service gets not affected by Doze Mode
wakeLock =
(getSystemService(Context.POWER_SERVICE) as PowerManager).run {
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyService::lock").apply {
acquire()
}
}
}
}
NOTE: I have covered all the possible use cases to restart the Service in case it gets killed by OS. There is one thing left if user restarts cell phone. This case can be found via other stackoverflow answers very easy. In Broadcast one just needs to start Service.
Step # 02
Make an application and register in manifest. And add below line of code in your application class.
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
val receiver = ComponentName(this, MyService::class.java)
val pm = packageManager
pm.setComponentEnabledSetting(
receiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
}
Here, MyService is the component name and this can be Service or Broad cast Receiver you are already using in you app. In my case I trie with Android service
Now, this is the time to register this Application class in Manifest file. Open the manifest file and in application tag use property name and place your application class name which was just created MyApplication.
Step # 03
There is no third step. You are done. You just install the apk and by this way Service will not killed even the app is killed. I tested the above solution on Vivo device and it worked
NOTE: In case, above solution does not work, please check the manifest file for allowBackup property if you find out this property in manifest file just remove it and uninstall the app and then install the app it will work for sure and then you can set that property again.
As far as I know, WhatsApp is whitelisted on the Xiaomi device autostart. There is nothing you can do about it. Of course your application will be whitelisted by Xiaomi if it eventually garnered as much as WhatsApp popularity. Until that happens, you can only asking for user to activate it manually by showing the Auto-start feature with something like this:
try {
Intent intent = new Intent();
if ("xiaomi".equalsIgnoreCase(android.os.Build.MANUFACTURER)) {
intent.setComponent(new ComponentName("com.miui.securitycenter",
"com.miui.permcenter.autostart.AutoStartManagementActivity"));
}
// context is your Context
List<ResolveInfo> list = context.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() > 0) {
context.startActivity(intent);
}
} catch (Exception e) {
Log.d("PERMISSION", e.toString());
}
Please note, that I haven't test the code for current Xiaomi device.
Related
I made a Xamarin.Forms project to create and show local notifications, and it's supposed to be able to put the app back to the foreground when the notification is clicked.
The thing is, my code works on Android 11 and before, but on Android 12 & 13 the notification click is received by the app, if I have a callback for that notification it is called, but the app stays in background.
This is the part of the code that runs when I received a notification click and that I want to set the app in foreground (this is in the Xamarin Android project) :
var packageManager = Application.Context.PackageManager;
Intent launchIntent = packageManager.GetLaunchIntentForPackage(Constants.PackageName);
if (launchIntent != null)
{
launchIntent.AddCategory(Intent.CategoryLauncher);
Application.Context.StartActivity(launchIntent);
}
I have found a lot of posts on how to start/set to foreground an app, and the code I use is what's working for others, but all these posts where from 2020 and before, so no Android 12+ at the time and I can't find anything about a new way of doing this.
Does anyone have this functionality working on the newest Androids ?
I have found the solution so I'll post it here if someone needs it.
The code I use to put the application back to the foreground is correct, but I was missing the System_Alert_Window permission in my main application.
So to handle this permission I did :
Add it to my main application's manifest
Create a native method that checks if it is enabled
Create a native method that redirect the user to the overlay settings so they can allow the permission.
To check if the permission is enabled :
public bool HasOverlayPermission()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.M)
return true;
return Android.Provider.Settings.CanDrawOverlays(Application.Context);
}
To redirect the user to their phone settings for AppOverlay (this permission can only be allowed from the settings) :
public void AskForOverlayPermission()
{
if (Android.Provider.Settings.CanDrawOverlays(Application.Context))
return;
var uri = Android.Net.Uri.Parse("package:" +
Application.Context.PackageName);
Intent intent = new Intent(
Android.Provider.Settings.ActionManageOverlayPermission, uri);
_mainActivity.StartActivityForResult(intent, 101);
}
The StartActivityFromResult method is only accessible in Activity classes, so you can either write it in you MainActivity or give your MainActivity as constructor parameter of another class.
This code will directly redirect the user to the settings page, so it's better if you ask them if they want to allow this permission in a popup or something beforehand (so they can understand why they're redirected).
I have found the code in this post : How to enable screen overlay permission by default
I'm having troubles opening system DND preferences from my App so that user can create or edit Automatic Time rule.
Current situation
Our app already has a similar feature which disables App-notification LED, sound and vibration for some specific time period (for example between 10pm-8am) and is applied app-wide. As of Android Oreo, our feature doesn't work anymore because of Notification Channels. The only solution is, as far as I understand, to create in System preferences Automatic Time rule which is then applied system-wide.
What I want to do?
Just to redirect Oreo user from my app to System preferences ie. Do Not Disturb preferences in order to add or edit Time rule.
The problem
There is no specific Intent which opens Do Not Disturb preferences. The closest one I could find was Settings.ACTION_ZEN_MODE_PRIORITY_SETTINGS which leads me to this Preference screen. I also found action which I exactly need, but as you can see, it is hidden by annotation.
Does this mean there is no way to open this Preference screen and I should use another approach?
I also had this question for a long time, now I finally found the solution that works for me:
Java
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.settings", "com.android.settings.Settings$ZenModeSettingsActivity"));
startActivity(intent);
Kotlin
val intent = Intent()
intent.component = ComponentName("com.android.settings", "com.android.settings.Settings\$ZenModeSettingsActivity")
startActivity(intent)
If you take a look at the AndroidManifest.xml for the Settings app you can see that there is an Activity Settings$ZenModeSettingsActivity (as mentioned by #cyb3rko in https://stackoverflow.com/a/63713587/467650) already from Android 5.0.
To send the user to the "Do not disturb" screen you can use the action android.settings.ZEN_MODE_SETTINGS like this:
try {
startActivity(new Intent("android.settings.ZEN_MODE_SETTINGS"));
} catch (ActivityNotFoundException e) {
// TODO: Handle activity not found
}
I would expect the intent filter to be even more stable than the class name.
this is the first time I ask a question on this forum: p
I made an android application that must work in the background ie when the phone is on standby to be able to recover the location of the user. I use a service and wakelock.
The application works on SAMSUNG but I noticed that HUAWEI kills the application if it is not in the list of protected applications.
So I create a dialog box to tell the user to activate the application in the list of protected applications as shown here: Keeping a periodic service active while the phone is locked
Since my app should run on all android phones I will want to know if there are other phones brands that kill the app when the phone is idle to do the same thing please.
Thank you in advance :)
I was facing the same problem and using accessibility I tried to get the class name or activity name to pass in intent and open the settings and looks like Old Protected app list is no more available, a new way is:
disable the application from Launch in HUAWEI
tested on Oreo Huawei p10:
For Manually you can go with below steps:
Settings -> Battery -> Launch
and find your application and disable
Programmatically:
public class Constant {
public static List<Intent> POWERMANAGER_INTENTS = Arrays.asList(
new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")),
new Intent().setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")),
new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")),
new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")),
new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")),
new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")),
new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.entry.FunctionActivity")).setData(android.net.Uri.parse("mobilemanager://function/entry/AutoStart"))
);
}
Put below code in Your Util or Activity Class
private static boolean isCallable(Context context, Intent intent) {
List<ResolveInfo>list=context.getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
saveUserSessionManager is a Preference, you can set your preference class instead of SaveUserSessionManager
public static void startPowerSaverIntent(Context context, SaveUserSessionManager saveUserSessionManager) {
boolean skipMessage = saveUserSessionManager.getDataByKey("skipProtectedAppCheck", false);
if (!skipMessage) {
boolean foundCorrectIntent = false;
for (Intent intent : Constant.POWERMANAGER_INTENTS) {
if (isCallable(context, intent)) {
foundCorrectIntent = true;
new AlertDialog.Builder(context)
.setTitle(Build.MANUFACTURER + " Protected Apps")
.setMessage(String.format("%s requires to be 'White list' to function properly.\nDisable %s from list.%n", context.getString(R.string.app_name), context.getString(R.string.app_name)))
.setPositiveButton("Go to settings", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
context.startActivity(intent);
saveUserSessionManager.storeDataByKey("skipProtectedAppCheck", true);
dialog.dismiss();
}
})
.show();
break;
}
}
}
}
How To call?
In your MainActivity in onResume method check its enable or not.
#Override
protected void onResume() {
super.onResume();
//saveUserSessionManager is just a Preference you can set your preference class instead of SessionManager
if (!saveUserSessionManager.getDataByKey("skipProtectedAppCheck", false)) {
Utils.startPowerSaverIntent(mContext, saveUserSessionManager);
}
}
Thats all :)
Holding a wakelock probably isn't what you want, since that doesn't necessarily protect your process from getting killed. The best thing you can do to increase the priority of your app's process is by making sure your Service runs in the foreground.
On Android O, the new way you get that to work is through startForegroundService(Intent)
This will put a notification in the notification tray which will tell the Android OS that your process is currently working. Then be sure to stop the service once your task is done.
For more information on Services in general, I'd check out the Service documentation. This will show you how to add the notification with the correct text.
It might also be helpful to brush up on how background processes work in Android O by checking out the Background Process documentation. If you're following that correctly (and starting in the foreground), your process should be as resilient as possible across all manufacturers.
The app I'm working on needs to run in background and uses a foreground service to this end. Starting from Android 8+ (maybe not only for these versions) many Huawei users are reporting that the app is being closed (W/O any notice) 6 7 minutes after the screen gets locked (I'm not see here and here).
Indeed, Huawei devices kill running apps by default to optimize battery consumption (cool right?). AFAIK there is no way to programmatically workaround this behavior. Many developers suggest users how to whitelist the app (see for example: Endomondo).
I'm also looking for a way to programmatically detect the optimization in order to at least warn users. Here you can find a possible solution but I haven't had time yet to give it a try.
I have two apps that both have kiosk mode enabled. I currently send a broadcast from one to the other that transmits data. I want to tell the receiving app to start a new activity.
In most cases I would be able to use intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); however... I am not able to start a new task while in kiosk mode.
Here is what I have in the broadcastReceiver(which I have verified works for other data). This code tries to start a new activity:
Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // this doesn't work in kiosk mode...
launchIntent.setComponent(new ComponentName("my.package","my.package.myactivity"));
try {
if(launchIntent != null) {
context.getApplicationContext().startActivity(launchIntent);
Log.i(TAG, "Started activity");
} else
Log.i(TAG, "Intent is null");
} catch (Exception e) {
Log.e(TAG, e.toString());
}
My error before adding the flag:
Kiosk Mode: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
And after adding the flag:
E/ActivityManager( 470): Attempted Lock Task Mode violation
Is it possible to send a context through a broadcast receiver, perhaps, so that I can start the desired activity using that context? Can anyone suggest another method other than using broadcasts to start new activity?
Note: In Android "ScreenPinning", "Kioskmode" and "Lock Task Mode" are the same.
from https://developer.android.com/about/versions/android-5.0.html#ScreenPinning
Once your app activates screen pinning, users cannot (...)
access other apps (...) until your app exits the mode.
You have to temprary disable the kioskmode with stopLockTask() interact and re-enable it with startLockTask()
To prevent android from asking the user to re-start kioskmode you also need to implement a https://developer.android.com/about/versions/android-5.0.html#DeviceOwner app
You can find a lot of infos about this topic at https://github.com/Tuong-Nguyen/Android/wiki/Research-114-Kiosk-Mode-Android-application
I am able to create an Activity that uses the DevicePolicyManager API's.
The tutorials show that I need use it the following fashion:
if (!mDPM.isAdminActive(mAdminName)) {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mAdminName);
intent.putExtra("wipe-data", DeviceAdminInfo.USES_POLICY_WIPE_DATA);
startActivityForResult(intent, REQUEST_ENABLE);
}
else {
mDPM.wipeData(0);
}
However I would like this to run inside a Service.
But I cant call
startActivityForResult
from within a Service.
So what would be the best approach or strategy for me to try ?
The only reason you need to call startActivityForResult() is if your app is not presently configured as a device administrator, to lead the user to go set that up for you. Hence, put that portion of your logic inside of your user interface.
Your service itself would just skip doing anything if isAdminActive() returns false.