I am having an inconsistent user experience due to the way android navigates back from Android Settings.
In my application the user needs to give my app access to ACTION_USAGE_ACCESS_SETTINGS, which I access with the following:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
After toggling the setting to on for my application, I need the user to return to my application. The only way to do this that I know of is for them to press the back button on the phone ( would love to know if it is possible to return automatically after the setting has been toggled!!!?!).
Now one of two things will happen:
1) The user has not used android settings recently, so it was not already open ( ie open in the open app drawer). The first press of the back button will take them to my application as desired.
2) The user had used android settings recently. Thus settings was already open in the application drawer. Now when the user presses back, Android will take them back through each setting page they had been using recently (ie the back button takes them through their history in the android settings pages). It may take 2, 3 or 4 presses of the back button to leave Android settings, and return to my application. This is obviously terrible UI/UX, and I was wondering if there is a better way?
I have noticed that when installing Google apps, after toggling the setting to ON, it automatically exits and returns to the application that called the setting. Being able to do that would be ideal, but I just cant work it out.
Thanks!
Ok, so after trying about a millions things, I have come up with 3 different ways to improve my problem.
1) Was provided by #CommonsWare, by removing the FLAG_ACTIVITY_NEW_TASK, it prevented an inconsistent number of back presses needed, and means every time the user would only have to press back twice.
2) Upon further research into the flags, I found that using three combined:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
reduced the number of back presses required to 1 single back press. This is simple and reasonable user friendly.
3) Using a handler to continuously check for the required permission after the settings intent has fired. This seems a like a bit of a hack, and I can't believe there is not a better way to do this, but it works exactly as it works when using a Google App. Ie, as soon as you switch the toggle to on, it exits the Android Settings page, and returns to your application, where you left off. I am using:
Handler handler = new Handler();
Runnable checkSettingOn = new Runnable() {
#Override
//#TargetApi(23)
public void run() {
Log.d(TAG, "run: 1");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Log.d(TAG, "run: 2");
return;
}
if (isAccessGranted()) {
Log.d(TAG, "run: 3");
//You have the permission, re-launch MainActivity
Intent i = new Intent(MainActivity.this, MainActivity.class);
Log.d(TAG, "run: 4");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
return;
}
handler.postDelayed(this, 200);
}
};
Then when you fire the intent to get to the Android settings page, just be sure to start the handler:
handler.postDelayed(checkSettingOn, 1000);
Hope this helps someone else with a similar issue.
After you have started Settings activity you can run periodical task, that is invoked every, for example 500ms, and checks if permission is granted.
Mark your setup activity with flag singleTask/singleInstance, and start it, if permission is granted. Existing instance of activity will be moved to top.
I did this for notifications access permission.
Extending upon Ufkoku's answer, I used a periodic check on the status of the permission. To get the user back, I used startActivityForResult and finishActivity.
Sample Code : I used this for the "USAGE_ACCESS_SETTINGS".
var intent = Intent("android.settings.USAGE_ACCESS_SETTINGS")
intent.data = Uri.fromParts("package", "com.example.app", null)
startActivityForResult(intent,101)
var timer = Timer(true)
timer.scheduleAtFixedRate(object: TimerTask(){
override fun run(){
if(checkUsageAccessPermission()){ // checkUsageAccessPermission() is a helper function
finishActivity(101)
cancel()
}
}
}, 0, 1000)
The solution from #Geordie Wicks was close to what I was looking for, but it seems like having the Android Settings open before launching your intent would cause the back button to take you to the previous Android Settings screen.
My solution involves two more flags, Intent.FLAG_ACTIVITY_CLEAR_TOP and Intent.FLAG_ACTIVITY_CLEAR_TASK.
You can define your intent as below:
Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
From my experience, this will make it so that a back button press will take you back to your application regardless of whether or not the Android Settings were open beforehand.
You can do one thing here. you have to confirm that you only open the settings component that you require to be opened .... Do not open the main settings app. Open only a single component within settings app that you want. So in that way when ever you will press back, you will jump back to your application.
For example if i want to open bluetooth settings in settings
application, I wont open the main Settings app instead i will open
only bluetooth component of settings. In that way when i press back i
will return to my own app because i haven't open the main setting app so i do not need to navigate in it.
ComponentName cn = new ComponentName("com.android.settings",
"com.android.settings.bluetooth.BluetoothSettings");
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent);
This is also the simplest way to navigate it
Sorry if the answer was late but I left my answer here for others to overcome this problems. To me the problems might be ourself not from Android. For e.g I have a listener, which listen to the state of the switch
setOnCheckedChangeListener { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data =
Uri.fromParts(
"package",
navigator.activeFragment?.activity?.packageName,
null
)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
navigator.activeFragment?.startActivity(intent)
}
What happened with this code?
The user go to Setting and then navigate back. If you have set something that update the UI like belows here after user go back, then this will cause multiple listener listen to the change of switch
override fun onResume() {
super.onResume()
if (!isFirst) {
// Notify that user might have change the notification setting
(binding.rvSetting2.adapter as SettingAdapter).notifyItemChanged(0)
}
isFirst = false
My solution
You may add this line inside the listener, this will remove the current switch listener, which can avoid go to Setting after and after when switch change.
setOnCheckedChangeListener { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data =
Uri.fromParts(
"package",
navigator.activeFragment?.activity?.packageName,
null
)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
navigator.activeFragment?.startActivity(intent)
// Remove the current listener in case of user went back from Setting and call on bind view holder again
// This cause multiple listener listen to the change of this switch
setOnCheckedChangeListener(null)
}
I know that this is just my personal solution, but if you share similar ways, this might be help.
You have to confirm that you only open the settings of your app that you require to be opened. Do not open the main settings app. Open only your app settings that you want. So in that way whenever you will press back, you will jump back to your application.
Uri uri = Uri.fromParts("package", getPackageName(), null);
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(uri);
startActivity(intent);
I call GooglePlay from my app through an intent and again after I kill my own app:
Intent intent = new Intent(Intent.ACTION_VIEW);
String sModule = "market://search?q=pub:mycompany";
intent.setData(Uri.parse(sModule));
startActivity(intent);
finish();
android.os.Process.killProcess(android.os.Process.myPid());
Task manager shows, that only GooglePlay is running. My app isn't there anymore.
So my focus is GooglePlay at the moment. When going to the Desktop through the Home-Button and calling my App again it directs me to GooglePlay again.
Why is that? How can I call GooglePlay from my app independently?
I expected that when starting my app again, which I had previously killed, it would start my app and not focus on google play.
keyword is "launchMode" and "task".
this type of problems are so annoying and much complicated in android.
but this time you can try this.
Intent intent = new Intent(Intent.ACTION_VIEW);
String sModule = "market://search?q=pub:mycompany";
intent.setData(Uri.parse(sModule));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
if u cant solve, try combine another flags with FLAG_ACTIVITY_NEW_TASK.
cheers!
My application needs QR code scanner app for running properly. There is no problem to request it like:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData( Uri.parse( "market://details?id=something" ));
startActivity(intent);
After this I am redirected to Google market with predefined application. However my problem is that this code exits my main application. It is not in list. Is this a correct behaviour? When you want to install some other application does it exit other applications? Or am I doing something wrong?
Main goal is to just bring to front my main application to use it after QR code scanner is installed.
Any help is appreciated.
Have you write finish() in your previous activity from where you are redirecting to google play activity. If you have written then remove it.
final String APPLICATION_PACKAGE_ID = "com.google.zxing.client.android";
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + APPLICATION_PACKAGE_ID)));
} catch(ActivityNotFoundException anfe) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://play.google.com/store/apps/details?id=" + APPLICATION_PACKAGE_ID)));
}
So I just make like it is. And when the application is installed I just hit back and it works. I dont understand how didn't work this in friday but now it is ok.
I have a button in my app named "Go Home" to redirect the user to the home screen. It is working fine without the very first launch. The process of first launch is noted below:
After uploading the APK into SVN I am downloading using the web browser. Then go back to the download folder and installing the app. When install finishes I click on Open. Then In my app I click on the "Go Home" button. The application redirect me to the web browser instead of the home screen. I am tired to search a solution for that.
I am using the following code:
finish();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
Thanks in advance, Siddiqui Noor
Your app is opening in the task of the browser. Try this:
finish();
Intent intent = new Intent(context, HomeActivity.class);
intent.setAction(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
try adding FLAG_ACTIVITY_NEW_TASK:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
and also try putting finish() after startActivity
I'm pretty sure that it's not really redirecting you anywhere, it's just closing the Activity. You call finish() after which the intent to start the activity never happens. The app is closed because you've finished the Activity and you end up looking at the screen that was showing before you opened the app. In this case, that is the browser.
Try removing the line to finish();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
startActivity(intent);
kill your current activity after redirect the next activity
finish();
Is it possible to send a activity into background programmatically in android?
I am creating a prank application that plays funny sounds after a specified time (input by the user). And I don't want the application to be visible when playing that sound and also the display should be dark.
Yes.
You can use either:
boolean sentAppToBackground = moveTaskToBack(true);
if(!sentAppToBackground){
Intent i = new Intent();
i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_HOME);
this.startActivity(i);
}
More information here: http://developer.android.com/reference/android/app/Activity.html#moveTaskToBack(boolean)
Or simply:
Intent i = new Intent();
i.setAction(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_HOME);
this.startActivity(i);
According to Romain Guy a Android Framework Engineer, "You cannot simulate a press on the Home key.". So beware...
Check: http://osdir.com/ml/Android-Developers/2010-03/msg01887.html
Updated this answer according to: moveTaskToBack(true) returns false always
This function ultimately works for you
moveTaskToBack(true)
Or download source code . Android minimize app programmatically
Maybe play the sound from a service instead?
To expand on the answer by #ns476, the reason you should play it from a service is that any Activity that is no longer in the foreground can be killed at any time by the OS. Please review the activity lifecycle.