Immersive mode instructions reappear every time the device enters this mode - android

My app uses the new "immersive mode" by calling (in onCreate):
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
This works great, but the "how-to" popup ("Swipe down from the top to exit full screen") appears every time the Activity is launched (if the phone is being locked while the activity was showing), even though the user has acknowledged the popup. As far as I understand, the popup is automatically generated by the system, so there's nothing I can do to change this situation, correct?
This issue is reproducible as follows:
Launch immersive Activity [no popup appears, only on the very first launch (correctly)]
Press the power button to switch off screen while the activity is showing
Press power button again to switch on screen
Close Activity by calling finish() e.g. from a button or menu option
Launch Activity again - popup reappears
The popup does NOT reappear if the activity is launched, closed, and relaunched without hitting the power-button in between. Also, it ONLY reappears if the activity was topmost while the power button was pressed.
Correction: The Activity needs to be closed by calling "finish()" (e.g. from a button or a menu option). It works correctly if the Activity is closed by the back-key.
I've uploaded a sample app here: https://github.com/niko001/com.greatbytes.immersivebug/tree/master/Test5
EDIT: There's now an Xposed module to disable the "panic mode", so I guess I'm not alone in seeing this is an annoyance ;)

Really interesting question! Thanks to your clear instructions, reproducing the issue wasn't a problem.
Alright, after digging through the source for almost 30-minutes and saying why would they do this? a bunch of times, I think I finally get it. I'll try to explain the best I can, but this is only my interpretation, and may not be correct:
Someone at android realized that the Immersive Mode will send people into a state of panic: how do i exit? (_sorry, I don't know what else the panic would be about_).
In this state of panic, the user will turn to the POWER BUTTON
.... > Power button --> User turns screen off (at x milliseconds since EPOCH)
.... > Praying that the navigation bar comes back
.... > Power button --> User turns screen on (at y milliseconds since EPOCH)
Now, the duration y - x is of significance. We'll discuss it a bit later, but first, let's look at how panic is defined:
panic happens when Praying the navigation bar comes back lasts less than 5 seconds. This value is held by:
mPanicThresholdMs = context.getResources()
.getInteger(R.integer.config_immersive_mode_confirmation_panic);
<!-- Threshold (in ms) under which a screen off / screen on will be considered
a reset of the immersive mode confirmation prompt.-->
<integer name="config_immersive_mode_confirmation_panic">5000</integer>
Ah, okay. So, it doesn't matter if the user has already acknowledged once, the prompt will be back if the above-mentioned criterion is met - even on the 100th launch.
And here's where the action happens:
public void onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode) {
if (mPanicPackage != null && !isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
// turning the screen back on within the panic threshold
unconfirmPackage(mPanicPackage);
}
if (isScreenOn && inImmersiveMode) {
// turning the screen off, remember if we were in immersive mode
mPanicTime = time;
mPanicPackage = mLastPackage;
} else {
mPanicTime = 0;
mPanicPackage = null;
}
}
(time - mPanicTime < mPanicThresholdMs) ==> ( y - x ) < 5000
unconfirmPackage(mPanicPackage) removes mPanicPackage (yours) from the list of packages stored under Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS.
Needless to say, I find this strange... and wrong. Even if the user is in panic, and takes the power button route, s/he won't see the helpful reminder until next launch. So, what's the point?
Or may be, I am wrong about the definition of panic.
so there's nothing I can do to change this situation, correct?
Correct. To fix this, you would have to add your package-name to value held by Settings.Secure.IMMERSIVE_MODE_CONFIRMATIONS. But, to write to a secure setting, your app requires WRITE_SECURE_SETTINGS permission - not for use by third-party applications.
Links:
ImmersiveModeConfirmation (helper class that manages showing/hiding of confirmation prompt)

More succinctly - in K, users will see the confirmation when entering immersive mode if:
They have not yet confirmed it for that app (package).
They "panicked" last time they were in immersive mode. "Panic" in this case means toggling the screen off, then back on in under 5 seconds (by default).

Related

Lock screen programatically when exiting app

Some apps in Android seem to be able to keep the screen on beyond the normal timeout (presumably done with FLAG_KEEP_SCREEN_ON), but on exiting the app lock the screen. I've seen this e.g. in navigation apps, that keep route guidance open, but the screen locks as soon as you leave the app.
How is this done?
(Note that the lock should happen when the application is goes into the background, not just when an activity is replaced by another activity within the same application.)
I managed to partially figure this out, based on "Launch activity when user taps on a notification from the lockscreen". Here is an example. Use this project https://github.com/googlesamples/android-CustomNotifications/ (e.g. Android Studio: File > New > Import Sample; look for ("Custom Notifications") and replace onCreate like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window = this.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.sample_main);
}
and in the manifest add
<activity ...
android:showOnLockScreen="true"
...
You now observe that the activity persists if
You press power button to turn off the screen. Press power button to activate screen, and your activity resumes without need to unlock screen.
You let the screen time out: Again, press power button to activate screen, and your activity resumed without need to unlock screen.
But: Once the screen has been locked at least once (through timeout or power buttons), then, when you navigate away from the app, the screen locks (which provides a partial answer to Lock screen programatically when exiting app).
However, it doesn't work when you navigate away before the screen has been locked at least once. Does anybody have suggestions?
Related question here: Launch activity when user taps on a notification from the lockscreen (secure unlock)

How to disable Home and other system buttons in Android?

I need to disable Home and other system buttons in my Android application.
Example: MX Player (see at Google Play) - you can press "lock" icon at player screen and it locks all hardware and software system buttons.
It works fine WITHOUT ROOTING.
I tested it on some devices with different Android versions. I tried to disassemble Kids Lock (plugin) but has no clue how it works yet.
I need same solution like the Kids Lock (plugin) for MX Player:
- disable Home, Back and all other system buttons.
Any suggestions?
First of, please think long and hard if you really want to disable the Home button or any other button for that matter (e.g. the Back button), this is not something that should be done (at least most of the times, this is a bad design). I can speak only for myself, but if I downloaded an app that doesn't let me do something like clicking an OS button, the next thing I do is uninstall that app and leave a very bad review. I also believe that your app will not be featured on the App Store.
Now...
Notice that MX Player is asking permission to draw on top of other applications:
Since you cannot override the Home button on Android device (at least no in the latest OS versions). MX Player draws itself on top of your launcher when you "lock" the app and clicks on the Home button.
To see an example of that is a bit more simple and straight forward to understand, you can see the Facebook Messenger App.
As I was asked to provide some more info about MX Player Status Bar and Navigation Bar "overriding", I'm editing my answer to include these topics too.
First thing first, MX Player is using Immersive Full-Screen Mode (DevBytes Video) on KitKat.
Android 4.4 (API Level 19) introduces a new SYSTEM_UI_FLAG_IMMERSIVE flag for setSystemUiVisibility() that lets your app go truly "full screen." This flag, when combined with the SYSTEM_UI_FLAG_HIDE_NAVIGATION and SYSTEM_UI_FLAG_FULLSCREEN flags, hides the navigation and status bars and lets your app capture all touch events on the screen.
When immersive full-screen mode is enabled, your activity continues to receive all touch events. The user can reveal the system bars with an inward swipe along the region where the system bars normally appear. This clears the SYSTEM_UI_FLAG_HIDE_NAVIGATION flag (and the SYSTEM_UI_FLAG_FULLSCREEN flag, if applied) so the system bars become visible. This also triggers your View.OnSystemUiVisibilityChangeListener, if set. However, if you'd like the system bars to automatically hide again after a few moments, you can instead use the SYSTEM_UI_FLAG_IMMERSIVE_STICKY flag. Note that the "sticky" version of the flag doesn't trigger any listeners, as system bars temporarily shown in this mode are in a transient state.
Second: Hiding the Status Bar
Third: Hiding the Navigation Bar
Please note that although using immersive full screen is only for KitKat, hiding the Status Bar and Navigation Bar is not only for KitKat.
I don't have much to say about the 2nd and 3rd, You get the idea I believe, it's a fast read in any case. Just make sure you pay close attention to View.OnSystemUiVisibilityChangeListener.
I added a Gist that explains what I meant, it's not complete and needs some fixing but you'll get the idea. https://gist.github.com/Epsiloni/8303531
You can use Android-HomeKey-Locker to disable HOME KEY and other system keys(such as BACK KEY and MENU KEY)
Hope this will help you in your application. Thanks.
I followed the shaobin0604's answer and I finally managed to lock the HOME button, by adding:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
to AndroidManifest.xml All you have to do is to copy HomeKeyLocker.java from shaobin's lib to your project and implement it like in shaobin's example. BTW: My AVD's Android version is Android 4.0.3.
You can disable the home and recents button Android 5.0, using the screen pinning feature mentioned here:
Android 5.0 introduces a new screen pinning API that lets you
temporarily restrict users from leaving your task or being interrupted
by notifications. This could be used, for example, if you are
developing an education app to support high stakes assessment
requirements on Android, or a single-purpose or kiosk application.
Once your app activates screen pinning, users cannot see
notifications, access other apps, or return to the home screen, until
your app exits the mode.
You can lock the device down to be a kiosk. The navigation bar is not hidden, but the home and recents buttons can be either removed or disabled depending how you activate the mode. I wrote some information after testing this feature here.
Just a guess, but I think with the SYSTEM_ALERT_WINDOW permission (displayed as "Draw over other apps", see here) it could be possible: display your app as a fullscreen, system alert type window. This way it will hide any other apps, even the homescreen so if you press Home, it won't really be disabled, just without any visible effect.
MX Player has this permission declared, and Facebook Messenger has it too for displaying "chat heads" over anything - so it might be the solution.
Update (added from my comments): Next, use SYSTEM_UI_FLAG_HIDE_NAVIGATION in conjunction with capturing touch events/using OnSystemUiVisibilityChangeListener to override the default behaviour (navbar appearing on touch). Also, since you said exit immersive gesture does not work, you could try setting SYSTEM_UI_FLAG_IMMERSIVE_STICKY too (with SYSTEM_UI_FLAG_FULLSCREEN and SYSTEM_UI_FLAG_HIDE_NAVIGATION).
It used to be possible to disable the Home button, but now it isn't. It's due to malicious software that would trap the user.
You can see more detailes here: Disable Home button in Android 4.0+
Finally, the Back button can be disabled, as you can see in this other question: Disable back button in android
If you target android 5.0 and above. You could use:
Activity.startLockTask()
First create a method :
public void hideNavigationBar() {
final View decorView = this.getWindow().getDecorView();
final int uiOptions =
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
Timer timer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
YourActivityName.this.runOnUiThread(new Runnable() {
#Override
public void run() {
decorView.setSystemUiVisibility(uiOptions);
}
});
}
};
timer.scheduleAtFixedRate(task, 1, 2);
}
Then you call it on onCreate() method of your activity.
Call it again on the onResume() method.
Then you may add another method in your activity like this:
#Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
hideNavigationBar();
}
That will be it.
Do remember it will lock the screen till the next time user touches the screen, in Timer class you can change the delay and it will allow you change things for that instance.Then it will lock the screen again.
I too was searching for this for sometime, and finally was able to do it as I needed, ie Navigation Bar is inaccessible, status bar is inaccessible, even if you long press power button, neither the power menu nor navigation buttons are shown. Thanks to #Assaf Gamliel , his answer took me to the right path.
I followed this tutorial with some slight modifications. While specifying Type, I specified WindowManager.LayoutParams.TYPE_SYSTEM_ERROR instead of WindowManager.LayoutParams.TYPE_PHONE, else our "overlay" won't hide the system bars. You can play around with the Flags, Height, Width etc so that it'll behave as you want it to.
i dont know how to diable home button.
as long as my knowledge i got folowing link.
refer the link:- http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_HOME
Key code constant: Home key. This key is handled by the framework and is never delivered to applications.
But,we can diable back button.
hope following code helps you out.
#Override
public void onBackPressed() {
//return nothing
return;
}
Refreshing an old topic.
I was able to achieve that my activity does not fold when the home button (physical or virtual) is pressed. Here is my code for activity onCreate() method:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarm_screen);
context = getApplicationContext();
int windowType;
if (Build.VERSION.SDK_INT>=26) windowType = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
else windowType = WindowManager.LayoutParams.TYPE_TOAST;
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
windowType,
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_FULLSCREEN,
PixelFormat.TRANSLUCENT
);
wm = (WindowManager) getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
mTopView = (ViewGroup) getLayoutInflater().inflate(R.layout.activity_alarm_screen, null);
getWindow().setAttributes(params);
//Set up your views here
testView = mTopView.findViewById(R.id.test);
wm.addView(mTopView, params);
On API 26 and abovem you need to get screen overlay permission from the user. Tested on Android 7 and 8.
You can't disable Home button from ICS onwords but can disable other buttons as follows
#Override
public boolean dispatchKeyEvent(KeyEvent keyEvent){
return true;
}
Post ICS i.e. Android 4+, the overriding of the HomeButton has been removed for security reasons, to enable the user exit in case the application turns out to be a malware.
Plus, it is not a really good practice to not let the user navigate away from the application. But, since you are making a lock screen application, what you can do is declare the activity as a Launcher , so that when the HomeButton is pressed it will simply restart your application and remain there itself (the users would notice nothing but a slight flicker in the screen).
You can go through the following link:
http://dharmendra4android.blogspot.in/2012/05/override-home-button-in-android.html
Using rotation causes an exception, So I've fixed my activity using this:
HomeKeyLocker locker;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_splash);
locker = new HomeKeyLocker();
locker.lock(this);
}
#Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
locker.unlock();
}
#Override
public void onConfigurationChanged(Configuration config) {
super.onConfigurationChanged(config);
locker.lock(this);
}
You will need to use the #LĂȘ Quang Duy suggestion.
I'm working on an application that needs to lock the tablet just for application.
First I put my app as MainLauncher, then I lock the taskbar using an AndroidView.
Finally I block the tablet.
It is not a feature that I indicate to use across multiple tablet models, since each device model has a feature to block it.
But overall it works for everyone.
You can use the commands
Java.Lang.Runtime.GetRuntime().Exec("su -c sed -i '/VOLUME_UP/s/^# //g' /system/usr/keylayout/Generic.kl");
as an example to disable the buttons. But everything is based on changing the system files, inside the folder "/ system / usr / keylayout / ...".
NOTE: Only works on rooted devices.
Another way I'm trying though still developing is using StreamWrite and StreamReader to access the RootDirectory and rewrite the whole file to disable and enable the buttons.
Hope this helps.
And any questions remain available.
For anyone looking to completely remove the soft-nav on a rooted (or custom ROM) android device, you can modify the build.prop text file within the system folder.
Set the following variable/value:
gemu.hw.mainkeys=1
This is what vendors use to disable the soft nav, when they have physical buttons.
Frankly it is not possible to disable the home button at least on new api levels , that is from 4.0 onwards. It is also not advisable to do that. You can however, block the back button by overriding the
public void onBackPressed() {
// do not call super onBackPressed.
}
in order to override the home button, you could use a timer for example, and after every time check if the main screen is your screen or not, or your package is on top or not, (i am sure you will get links to it), and display your activity using the flag single_top.
That way , even if the home button is pressed you will be able to bring your app to the top.
Also make sure that the app has a way to exit, because such kind of apps can really be annoying and should never be developed.
P.S: It is not possible to intercept the home event, when the home button is pressed.
You can use on attach to window methods and also keyguard methods, but not for api levels from 4.0 onwards.
Sorry for answering after 2-3 years. but you can hide activity of all system buttons. Just check this my answers How to disable virtual home button in any activity?.

How to prevent user from closing application - Android 4.0.3

So my question is: If is possible to prevent user from closing application.
Problem is because i can't hide action bar and i use tablet only for work time registration. So if someone press home button or back button is that not acceptable.
So i wonder if i could somehow handle onclose event?
Is it possible to open application in fullscreen (with no action bar)?
You cannot prevent user from closing application if he presses home button. That's the whole idea of it. Otherwise, you could leave user trapped in your app with no means to exit but to reboot it's device.
Short answer is no.
Long answer is that you can make it quite difficult for the user to close you app. Some of the tricks that can be used are: reopen you app as soon as it closes , disable keys like back and power and finally disable the home button
A user will always be able to close an application, otherwise there would be programs abusing it and causing problems, but there are steps you can make to better handle it being closed.
For example, if you have a remote service running that can check if the application is running, and there can be various ways to know, then it could fire off an intent to start the application again.
One way to know if a program is alive is to have it periodically call the service, basically doing a heartbeat check, and if it hasn't been called in some period of time, which should be 2 or 3 times larger than the expected check-in period, then fire off the intent.
There are other steps that may work, if you detect that the home button was pressed, but I would need to think through those steps. I think it depends on your expectations though, as trapping someone in your program would be really bad.
try this...
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//Remove notification bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
Ref-> How to hide the title bar for an Activity in XML with existing custom theme
to prevent the user .......
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode==KeyEvent.KEYCODE_BACK || keyCode==KeyEvent.KEYCODE_HOME){
// pass some msg ......
return true;
}
return super.onKeyDown(keyCode, event);
}
So here is my solution that works...
First you install trial version of SureLock application. Then in that app disable action bar. And thats it.
If you want to view again action bar you will need HideBar app
All of that works only on rooted devices...

Android Back-Button-Cycle Issue

I'm ware of androids life cycle and that it's not needed to add a "exit" button in the application.
But still, this back button stuff isn't really working out well.
You maybe know this issue from the default SMS-App that android comes with: you open it when you get a new message and exit it using the menu button or something else.
After like 20 times doing this, you then decide to exit the app using the back button, what happens? you have to go back though 20 views. every time you press back you return to the "all messages (by sender)" listview and when you press back there again you return to the message opend 20-1 (message 19). again you press back and return to the listview and again you press back and end up at message 18. till, after40 times pressing back, you finally exit the messanger app.
same happens when for example you got a action bar with a "home" icon which opens the main screen of your app. the user picks a action and the new activity starts. than the user clicks the home button and returns to the main screen. when pressing the back button - no matter if you call finish() in the onButtonBack listener or not, you the user would expect the app to exit, but in fact the app returns to the previous activity which is wrong.
such cycleing may happen for various reasons, thats why - even thought i'm aware of the supposed to be lifecycle of android - i wan't to EXIT (& destroy) the app when pressing back within a defined activity.
calling finish() dosn't help. if there's a previous activity it will re-open it. calling system.exit(0) isn't nice to do.
so: whats the right way to prevent such back-press-cycles and/or exit a application (WITH destruction)?
for better illustration of what i want to achieve: consider A, B, C being activities. a arrow (-->) illustrations a new intent call from the activity leftside of the arrow, rightside of the arrow represents the activity that is called. ex.: A --> B means activity A starts activity B. now here's what i want:
1) A --> B --> C pressBack:--> B pressBack:-->A pressBack:--> Exit
2) A --> B pressBack: --> A pressBack: --> Exit
3) A --> B --> A pressBack:--> Exit
as you see, back works as always, BUT when in activity A it exits the application.
the behaviour i got now is 1) and 2) as above but
3) A --> B --> A pressBack:--> A pressBack: --> Exit
keep in mind, i've already overwritten the onBackPressed listener of activity A with a finish() call. even calling system.exit(0) dosnt work. however, even if it would: its not what i want, i want the REAL way to do it android style - i cant imagine system.exit(0) is best practise.
Well this is the default behavior.
If you have another approach, just implement it.
One approach to deal with this is to use the android:launchMode="singleInstance" for activities that can be launched in a singleton manner (only one activity can exist)
For example, if the SMS page in the SMS app was a singleTop, it would have needed only one back press to remove all the SMS pages. It is a matter of choice
Another more aggressive way would be to finish Activities when you start another activity. Of course, such decision would risk making the app less friendly (android users are not accustomed to this behavior). Nevertheless, if this is used only where it may be considered acceptable then it might be acceptable.
A very acceptable place to do this would be a login screen: Once login is successfull, you start another activity (probably designed for logged in users) and finish the login activity.
Enjoy Finally, in my personal opinion, you can add an Exit button. Users will find it nice.
Check my post: Adding an Exit button to Android Application

Weird Home button behavior

I'm experiencing kind of strange behavior of my application after hard Home button is pressed.
When you press Home, everything is OK - my app goes to the background, showing Home screen. But if you try to choose my app in the main menu or in the list of last tasks it behaves like it was not started before and does not show the last activity you were on - it just starts from scratch, namely, shows the splash screen and starts next corresponding activities. Moreover, old activities of this app remain on the activities stack, and previous instance of the app is not terminated - so if you press Back for a few times you'll just run into those activities which were undoubtedly started during the previous session of work with my app. Splash screen activity is filtered by "android.intent.action.MAIN" filter and "android.intent.category.LAUNCHER" category.
The strange thing is that all of that happens despite the fact that I do not intercept any Back key hits, or override any onPause or onResume methods. What's happening contradicts with my understanding of Android app lifecycle - I was sure that when you hit Home an app just goes to the background, and when you choose it in the menu later - it just unwinds and does not start anew. (Of course, unless stuff like that is stated in the app manifest or corresponding methods are overridden or something else).
I also checked it for some other lifecycle events - such as changing orientation or flipping hard keyboard out - and none of those led to such strange results. It appears that the problem occurs when you try to start the app from main menu or menu of last applications.
I hope you will be able to help me. Any advice on what to pay attention to or where to search for solution would be really great.
Regards, Alex
You need to set android:launchMode="singleTask" in your LAUNCHER activity in your manifest file.
For more info on the launchMode attribute see here
Note that:
The default mode is "standard".
and:
Every
time there's new intent for a
"standard" activity, a new instance of
the class is created to respond to
that intent.

Categories

Resources