I want to allow users to lock the device in a sports activities tracking app, to avoid unintentionally leaving the app while exercising.
Therefore I provide a button which locks the input controls of my app and in addition provides the option to lock also the home and overview button, by calling Activity.startLockTask().
I know, that I can call ActivityManager.getLockTaskModeState() later on to find out, whether the user accepted the lock or not.
But what is the best time to do that, or in other words, is there a reliable event that is called, when the popup provided by the system is accepted or rejected by the user?
I checked already that onResume of my activity is not called.
I also found DeviceAdminReceiver.onLockTaskModeEntering/Exiting. But this is meant for administrated devices only and I don't think it can be used without a lot of additional hassle (if possible at all).
I also hoped that the view, which is temporarily hidden by the system popup, gets any of its onWindowFocusChanged, onWindowVisibilityChanges or any other "onWhateverChanged" methods called. But no breakpoint was hit in the methods I tried to overwrite.
Related
By "interruption" I mean something like receiving a call and answering it, putting the phone call over the application, receiving a popup whatsapp message on top of the application and so on, with the interruption always being caused by an external app.
I've tested my app in APIs from 19 to 25, except for 20 and in this APIs what fires with that interruption is either a onSaveInstance and onResume events or just a onResume event.
But in API 18 that "interruption" forces a onStop(). Problem is that in my app if some conditions are met on that onStop function the app must finish, and unlucky enough if the "interruption" comes in this version that conditions happen and the app finishes.
Would be there any way to force app to react with a OnSaveInstance, OnResume or just onResume like other versions? Or any way to tell the app that the onStop() is being caused by an external app?
Don't bother trying to figure out what "caused" the onStop(); the framework is just doing its job by keeping you abreast of the activity's Lifecycle. (If you find that other API levels behave differently, it may be because they use transparent overlays or something during certain "interruptions," and therefor the activity is still technically on-screen).
The root cause is an application design issue. You may want to reevaluate when you choose to "process the user's input" (or whatever it is you're currently doing in onStop()). By choosing onStop(), you're telling the system, "I want you to run this whenever the activity goes offscreen," and with the wide variety of devices & API levels that are out there, that can happen at many different times.
Consider having the user press a button when it's time to "process the input." Or, you may want to move the processing to a different "layer" of the Activity Lifecycle; to onResume()/onPause(), perhaps, or onCreate()/onDestroy().
After reading through all the questions on SO regarding this topic i am extremely annoyed by this.
Crashes will happen, no one writes perfect code. And there are apps that require a certain logical hierarchy. The best example is the login-screen idea, where you are in some activity doing something on a server and now the app crashes. After a restart, the app lost all its login-session data and saving it might not be the safest idea. So presenting the user with the login screen after a crash would be the best and most logical thing to do. The best user experience.
However Android decides to remember the Activity stack but only restart the last working activity with a "blank" application under it.
The only viable option i see would be to check in EVERY single activity if some login state is available or not and if not, start the login (launcher) activity with a clear-top or clear-task. But this almost forces you to write a base extends Activity class in which this behavior is implemented and then all activities have to extend that. But what if, for some reason, you cannot extend it because you need to extend some other type of activity?
There is android:clearTaskOnLaunch but this happens every single time the user returns from exiting via home button. There is the antagonist finishOnTaskLaunch that finished an activity every time the user presses the home button. So the Android devs are aware that sometimes one would like the app to appear in a certain state after exit but a crash seems to be exclusive to all that.
Using a custom UncaughtExceptionHandler gives me some chance to act after a crash but as the apps state is unrecoverable i can only perform certain tasks that will happen in addition to Android very own behavior.
So my simple question is, if there is any way, that is built into Android, that allows me to change the after-crash-behaviour of Android in a natural way that does not depend on the version it's running (to some extent ofc) and will result in a somewhat smooth user experience.
I would say the proper way of obtaining the result you would like would be to provide a proper parent or up navigation stack. You can read about it more here https://developer.android.com/training/implementing-navigation/ancestral.html.
But the gist of it would be to use the idea of parent activities to provide proper back navigation. If the activity already exists it will just go back to it, if it doesn't (such as in the crash scenario) it will launch the correct activity when the user navigates back.
NavUtils is a handy class to help build this behavior and is part of the support library which would work on a range of different API levels.
For reasons outside of my control (so, please no "you're doing it wrong" replies), my Android app needs to play extremely nicely, i.e. when a user hits the home button, my app needs to go away and release all of its resources (which are heayy, more than 1GB RAM consumption etc). It seemed calling finish() in onPause() would do the trick, but here's the problem: onPause() and onStop() also get called when I start an activity of my own, e.g. a preference activity, for which I just want to normally return.
So, my problem is: How can I determine the reason for losing the focus? I can think of two options, neither of which are pretty:
Keep state, i.e. the new activity sets some global flag that I can check in the "covered" activity so it doesn't stop when onStop() gets called. Annoying because every new activity of mine would have to do that.
Use the ActivityManager to check the top activity, and if it's one of mine, don't commit suicide. Maybe better, but the documentation heavily discourages use of the ActivityManager for this type of stuff.
Any ideas?
You are welcome to use onUserLeaveHint(). It may cover some scenarios (e.g., HOME), but not all (e.g., incoming phone call).
please no "you're doing it wrong" replies
IMHO, "more than 1GB RAM consumption" is already "doing it wrong" for a Play Store app. Specialized apps (e.g., specific enterprise scenarios, dedicated hardware) might be able to get away with that.
One approach for option 1 that will make it less annoying to implement and maintain would be to use Application.registerActivityLifecycleCallbacks. At least this way you don't have to implement this logic multiple times in multiple classes or unnecessarily force your activities into a single otherwise unrelated base class.
Not that I necessarily endorse this option. Also note you'll need API 14+.
SECURITY ISSUE: I don't now how it happens, but readers of this questions come up with idea that solutions to this problem is a security threat. So please keep in mind, all data I am interested in is measuring time of user in/activity. That's all. What user did -- I am NOT interested at all!
What I need is very simple concept, but I cannot find a solution. I would like to run a process (in the background) and have a listener to user interaction.
So, user touches screen --> my method is triggered.
User unlock phone --> my method is triggered.
User types on physical keyboard --> my method is triggered.
So in short my method is NOT triggered when the phone lies still on the table :-) Please note, that the interaction is with entire phone, not with my app, and I am not interested that user typed letter "K", I am not even interested that user typed something, all I care is the user used the phone in some way.
Btw. the state when user is walking listening to music (phone in the pocket) -- it is NOT interaction.
What I am looking for is a trigger -- something like INTERACTION_DETECTED, or (conversely) a callback method which is set like reportInactiveUser(10*1000) and it would be called if user was inactive for 10 seconds.
QUESTION how to detect user interaction?
Purpose: to measure the time of using manually the phone.
(lack of) PROGRESS
I found out that BatteryStatsImpl could hold the data I need. The instance of it is kept by BatteryStatsService, which however does not let any access to it, only IBatteryStats which in turn has only one interesting method -- getStatistics and the output does not include user activity counters (or they are all zeros; I set all permissions on). So, so far -- bad luck.
All calls have to be made by reflection, because those classes are not available anyway ;-).
You want to intercept physical interactions with the phone for that.
For screen touches, this package will come handy. *You can use this to listen for gestures on the screen.
For physical button touches, I suggest you have a look at this.
I'm building an Android application that's based around an enhanced WebView (based on PhoneGap). I've enhanced the WebView so that from JavaScript running inside you can invoke the native contact picker to choose a phone number (which may be supplied by Facebook for example).
The problem I have is that the native contact picker runs in an activity in another process and the Android docs say that while another activity is open my activity may get destroyed due to memory constraints. I haven't actually seen this happen in my application but if it did then I'm guessing my WebView's state would be destroyed and the code that was waiting for the picked contact would be terminated.
It seems a bit crazy that the activity requesting a contact could be destroyed while the contact picker is open. Does anyone know if that does indeed happen? Is there a way to persist the state of the WebView if it does?
Thanks,
-Shaun
Does anyone know if that does indeed
happen?
You're looking at the problem too simply.
You have a WebView. You open the contacts application. While the user is in the contacts application, a phone call comes in. While on the phone call (using a Bluetooth headset), a text message comes in, so the user opens that up from its Notification. While still on the phone call and texting away, a text comes in with a link, so she taps it and brings up the Browser application.
By this time, your activity is surely destroyed, except on maybe some of the most recent phones that have a fair bit of RAM.
Now, is that common? No. However, this also has nothing to do with the contacts application -- if the user presses HOME, at some point in the future, your activity may be destroyed to free up RAM as well.
Is there a way to persist the state of
the WebView if it does?
That depends on what you consider "the state of the WebView" to be. This really is PhoneGap's job, if you are making a PhoneGap-based app. So, you might consider asking them.
There is no way to persist the DOM. There are trivial ways to persist the URL (see onSaveInstanceState()). And there may be stuff in between that you consider part of "the state of the WebView" that may or may not be possible to save.
The long and detailed answer is a bit complicated, but essentially it comes down to a few points:
If the Android OS has to go cleaning up Activities or Services, it knows how to prioritise which ones should go first. It does this based on whether they're currently in the foreground (last to go), in the middle of executing code, waiting for a result, or simply sitting inactive in the background (first to go). You can be reasonably certain that if your WebView Activity launched the contact picker using the startActivityForResult, it won't be killed
There's a whole system for saving data if an activity is killed, such as the onPause method (which are triggered as soon as your activity leaves the foreground), the onSaveInstanceState method which is called when your activity is about to die. Read up on those to get more information, and the configurationChanged method when the screen orientation changes. If you haven't at least skim read the Activity Lifecycle document on the developers page, you must do that.
Lastly, I'm sure this question has been addressed many times, but with slightly varying wording or situations. Have a look around, see what else you can find.