Can I trigger sleeping background trigger from secondary tile of UWP app? - triggers

I have this code for creation of secondary tile:
var logo = new Uri( "ms-appx:///Assets/Square150x150Logo.png" );
var tile = new SecondaryTile( "TileID", "Tile Text", "ActivateChange", logo, TileSize.Default );
await tile.RequestCreateAsync();
then I have code in my App's OnLaunched(LaunchActivatedEventArgs args) for checking if App was launched with "ActivateChange" arguments:
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
if (!string.IsNullOrEmpty(args.Arguments) && args.Arguments == "ActivateChange")
{
//Doing some work
this.Exit();
return;
}
...
The problem is that when I click on secondary tile then splash screen appears, after it dissappears then it does some of my work and after that it exits the app.
What I would like for it to do is that when I click on secondary tile it will trigger some background task asociated with my App and this background task will do some of my work and then changes its state to sleeping or exits. I don't know how they work. I just know that I can have background task that is running all the time and triggers periodically on some time. But can I have background task that is somehow sleeping and can be triggered from secondary tile?
Thanks!

Live tiles are only meant for starting the app. The only difference between the primary and the secondary tile is that the secondary tile can pass an additional launch argument to the application, and you are already taking advantage of that.
In my opinion, it would be a strange experience for the user anyhow, if nothing seemed to happen when he clicked on the tile. Well, even having the application automatically quit when clicking on the secondary tile (as you are doing it now) is a strange behavior, akin to application crashing unless the user knows better.
It's difficult to suggest an appropriate alternative without knowing what you are trying to achieve. There is no way to trigger a background task by a user action from outside the application. You could use the ApplicationTrigger inside the app instead of doing the work directly which would allow you to close the app sooner. You can also look at the complete list of available triggers - it's all the classes ending in Trigger on the linked page. Maybe there's one there that would work better for you.

Related

what is the difference between ActivityStack and TaskRecord

I'm studying with AOSP, and I found ActivityStack and TaskRecord in "ActivityStack" Class. There is explanation In https://developer.android.com/guide/components/tasks-and-back-stack , Back-stack(=Activity Stack) And Task seems similar to me... What is the the difference between ActivityStack and TaskRecord?
In this https://developer.android.com/guide/components/tasks-and-back-stack,
Focus on below lines, For Task
A task is a cohesive unit that can move to the "background" when users begin a new task or go to the Home screen, via the Home button. While in the background, all the activities in the task are stopped.
For back stack
The back stack for the task remains intact—the task has simply lost focus while another task takes place. A task can then return to the "foreground" so users can pick up where they left off.
For info you can refer below links:-
What is the relationship between Task and Back stack
https://blog.mindorks.com/android-task-and-back-stack-review-5017f2c18196
https://medium.com/google-developers/tasks-and-the-back-stack-dbb7c3b0f6d4
If you think of activity back stack as two levels, it might be easier to understand the purpose of ActivityStack. Android supports launchMode and taskAffinity to put activities into different TaskRecords. But even activities are put into different TaskRecords, it keeps supporting the back button to switch back to previous activity. So when you launch activity that needs to be in new TaskRecord, then back button is pressed, it switches to top activity of previous TaskRecord. So ActivityStack is more like a TaskRecord stack, and TaskRecord is more like the activity stack inside the TaskRecord, however, general speaking, ActivityStack controls the pop up sequence, and you can say it's an indirect activity stack.
And creating ActivityStack seems to make management easier logically in multiple window environment. If you enable free form in Android, each launched window mode app has its own free form stack, and each stack has its own back stack.
My 2c.

Swift: Clearing .sharedApplication().shortcutItems on application quit

I'm having a very simple problem with my implemented 3D Touch dynamic quick action shortcuts.
I want the shortcuts to be cleared whenever the app is terminated (by double clicking the Home button and swiping up).
I am calling UIApplication.sharedApplication().shortcutItems.removeAll() as follows:
func applicationWillTerminate(application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
UIApplication .sharedApplication().shortcutItems?.removeAll()
self.saveContext()
}
However it has no effect, and the quick actions still show when 3D touch is used.
If I place UIApplication.sharedApplication().shortcutItems?.removeAll() inside
func applicationDidEnterBackground(application: UIApplication), this works exactly as intended...
I read something about applicationDidEnterBackground being the function used in most cases due to background processing or something...but there has to be a way to achieve what I want when the user terminates the app using the app monitor swipe up.
Thanks
Didn't tried this. But this tweak should work.
Start a background task on applicationWillTerminate and end it after some small delay. In the mean time, you can call 'UIApplication .sharedApplication().shortcutItems?.removeAll()'.
This will hopefully clear the shortcut items.
There are dynamic and static quick actions. The first kind you define through the shortcutItems property of the UIApplication instance (like in your example). The second kind you register in the plist file.
From the documentation:
Your code creates dynamic quick actions, and registers them with your app object, at runtime.
The system registers your static quick actions when your app is installed.
If a user installs an update for your app but has not yet launched the update, pressing your Home screen icon shows the dynamic quick actions for the previously-installed version.
This means that even when the app is closed the system remembers about both kinds of quick actions. While your app is in memory, such as when going into background, the system can still query the UIApplication for the dynamic actions but it must keep some other sort of persistence of quick actions when the app is closed.
I think there is just no guarantee about the point at which the system synchronizes with the dynamic quick actions. My guess is that the system does not necessarily synchronize when closing the app, yours might be an unsupported use case.

Back and volume buttons not working when app is resumed in certain conditions

I'm starting a new activity to display a leaderboard in my Android App.
When the leaderboard activity is displayed, and the user presses the home key and then resumes the app (so the leaderboard activity comes up again), and then navigates back to the main activity by pressing the back key, the back key and volume keys stop working).
I've attempted to override onBackPressed in my activity class. I can confirm that when this problem occurs, onBackPressed is not called (When back / volume is working, pressing back does trigger onBackPressed).
Normally I get a message in LogCat when I press the back key 'Unimplemented WebView method onKeyDown called from android.webkit.WebView,onKeyDown(WebView.java.2178)' - Again I can confirm that this message doesn't come up when the back key isn't working
Armed with the above information, I can only assume that it's something to do with the View not having focus or something along those lines. I would point out that touch input on the screen itself does work. It just seems to be the back and volume keys/buttons that have no effect.
It's an openGL ES 2.0 app so in my onPause() I'm calling view.onPause(); and in onResume, I'm calling view.onResume();
I really have no idea what's going on and I've been on this for 3 days straight so if anyone can point me in the right direction, that would be great.
If the user comes out of the leaderboard and back into the main app before they press the home key, then everything is OK, it's just if the home key is pressed while the leaderboard activity is displayed as described above.
So when I'm at the point where the back / volume keys aren't working, if I click my scores button and fire up the leaderboard activity again, they work. On returning to my activity, they stop working again.
Not sure if this is relevant at all but the following shows how I'm starting my leaderboard activity:
if (scoresButtonPresses){
displayLeaderBoard();
}
void displayLeaderBoard(){
//Display the leaderboard if already signed in
if (checkSignedIn()){
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), leaderboardID), 1);
}
//if not already connected, then set flag and connect to play services before displaying leaderbaord
else{
signInAction=SHOW_LEADERBOARD;
getGameHelper().beginUserInitiatedSignIn();
}
}
#Override
public void onSignInSucceeded() {
//If the flag is set, then display the leaderboard
if (signInAction==DISPLAY_LEADERBOARD){
startActivityForResult(Games.Leaderboards.getLeaderboardIntent(getApiClient(), leaderboardID), 1);
}
//Otherwise, reset the flag and take no action
else {signInAction=NO_ACTION;}
}
This is driving me crazy so any help or even a nudge in the right direction would be very much appreciated!!
Edit
After much testing I have learned a couple of things:
If I remove the view.onPause() && view.onResume() the problem seems to go away. So this appears to be something to do with the way key events are captured by the view. Pausing and resuming seems to mess something up.
I have also tried removing the view.onPause() and view.onResume() as above, but instead, putting in View.setVisibility(View.GONE); and then making it visible again in public void onWindowFocusChanged(boolean hasFocus). Again, I get the same problem. Interestingly, when I open the leaderboard, as expected the view's staus is 'gone' then hitting the home key and running the app again, it's set back to 'visible' - I don't understand this behaviour but I'll ask another question for that.
Lastly, and this I find really odd. If I put my app back to as I had it, then after hitting the home key and relaunching the app via Eclipse (and I can do this multiple times) the problem doesn't seem to occur. So in that respect, it appears to be something to do with touching the screen.
Edit
It appears as though this isn't limited to my app. I've tested this on a couple of other apps from the Play store and get the same result.
One app clearly uses a single activity model like mine and the back and volume stop working throughout the app.
The other may use a different activity for it menu and game. When I test on this app, the back/volume breaks but if you start a game (therefore a second activity), the back key starts working again, even when you return to the first activity (recreated this activity?!)
So maybe I can get around this by ensuring the activity is recreated? I thought i was already but maybe I'm not getting something. Maybe it's something to do with the stack.........
I have no solution to your problem but some additional insights since I'm facing the same bug/problem with the leaderboards and the back button (and it's driving me crazy).
I'm using a single activity with fragments from which I login to Google Play, open Leaderboards and Achievements in the exact way you are doing it (startActivityForResult). Always when I come back from any Google Play Service activity my back button is broken. Sometimes it's even enough if I try to login to Google Play for it to break, meaning the login popup sometimes breaks the back button (but not always).
Some more insights which might help to solve the problem:
I'm not using OpenGL, so it's not related to this - I'm just using a single activity and fragments
It's also breaking for me when I just use the back button for going back from any Google Play Activity (I don't even need to go via the home key, just normal back is enough).
When the back button is broken the Activity is not receiving any Key Events (OnKeyDown, OnKeyUp, dispatchKeyEvent) are all not working, although using the activity and touching it fully works. My guess is that some view is catching the events...
Edit:
I also tried checking activity.getCurrentFocus() and activity.hasWindowFocus() as well as the parent and context classes of activity.getCurrentFocus() to see if there is any difference between when it's working and when it's not - and there isn't any difference...
Edit:
It seems that a simple call to View.requestFocus() is fixing the problem. For my single activity (using fragments implementation) I have now added:
#Override
public void onResume(){
super.onResume();
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragmentContainer);
fragment.getView().requestFocus();
}
and this seems to be fixing the problem. Sill have to do long term checking if it's always fixed. In your OpenGL implementation I guess you will have to get the main view of the activity in some other way since you are not using fragments.
I know it's pretty old question, but for clarification: accepted answer is correct, but incomplete. Focus requesting should be done in onResume, onActivityResult, onSignInSucceeded and onSignInFailed. In first two you have! to call super. Some code:
private void requestFocusAfterGooglePlay(){
if(gimmeFocus==null)
return;
View currFocus=getCurrentFocus();
gimmeFocus.setFocusableInTouchMode(true);
gimmeFocus.setFocusable(true);
gimmeFocus.requestFocus();
gimmeFocus.setFocusableInTouchMode(false);
gimmeFocus.setFocusable(false);
if(currFocus!=null)
currFocus.requestFocus();
}
#Override
public void onSignInFailed() {
requestFocusAfterGooglePlay();
}
#Override
public void onSignInSucceeded() {
requestFocusAfterGooglePlay();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
requestFocusAfterGooglePlay();
super.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onResume(){
super.onResume();
requestFocusAfterGooglePlay();
}
in my case gimmeFocus is a dummy View created as below:
<View
android:id="#+id/gimme_focus"
android:layout_width="0px"
android:layout_height="0px"
android:focusable="false"
android:focusableInTouchMode="false"/>
I have dynamic layout so I can't never be sure that any view exists in my layout, so I've created this dummy View, it might be also added programmatically. You might choose your fixed View for gaining focus, but rembember that changing focus might change view's look (drawable state).

Robotium : Is there a way to check for an activity to NOT exist?

I'm automating an app that shows some overlay messages anywhere on the app for several scenarios, such as app installed for the first time etc. (I'm fairly new to Robotium too.)
The overlay displays a text that goes away by swiping or clicking on it. Also, there are different types of these overlays with different unique text on it. (let's call it Activity A)
I wanted to create a robust test case that handles this case gracefully. From the test's perspective we won't know that the activity A will be present all the time. But I want to recover from the scenario if it does, by writing a method that I can call any time. Currently, the tearDown method gets called since my expected activity name doesn't match.
Also, even if the activity A exists, there are other predefined overlay texts too. So, if I use solo.waitForText("abc") to check for text "abc", I may see the overlay 2 with the text "pqr" instead.
So I was looking for a way to automate this, and I can't use solo.assertCurrentActivity() or solo.waitForActivity methods as they just stop the execution after the first failure.
So any guidance is appreciated!
All the waitFor methods return a boolean. So you can use waitForActivity() exactly as you want to. If the Activity doesn't exist it will return false.
You can check which Activity is current:
Activity current = solo.getCurrentActivity();

Prevent cached iPhone webapp from reloading (scrolling to top)

I have an iPhone webapp that uses a cache manifest to work offline. I add the webapp to my home screen, use it (say scroll to a certain location on a page), then go back to homescreen.
When I open the app again, for a brief moment I see where I used to be (at that scrolled location on that page), but then the app "reloads" and I get scrolled to the top of the mainpage. Is there a way to prevent this "reloading"? This happens even in airplane mode (ie everything is working off the cache).
You're just seeing the default startup image, which is just a screenshot of the last place you were at. It's not "reloading"; the app wasn't loaded to begin with.
Search for "apple-touch-startup-image" to set a real loading image.
What I'm struggling with here is that the app actually seems to stay "in memory" longer if I use regular Safari as opposed to running in "apple-mobile-web-app-capable" mode. In the later case something as simple as pressing the home button, then task-switching back to the app causes a reload. Doing the same thing just in Safari often does not reload. So I'm worse off by using "apple-mobile-web-app-capable".
I don't believe there is a real 'reload' event. onload and onunload are all we get.
the onload handler starts up as if it is your first time coming to the page.
the onunload handler is the key to clearing out old content.
I like to provide alternate content for people who are coming back to my web app.
window.onunload=function(){
document.getElementsByTagName('body')[0].className+=' unloading'
}
And let the CSS do the dirty work to hide most of the body and show alternate content.
(this answer does not rely on jQuery or other frameworks)
// on load
window.scroll(0,0);
To ensure no old content is displayed while launching I use this in my page:
window.addEventListener('unload', function() { $('body').hide(); } );
Thus the last state of the page is empty and is what is shown to the user when the page is opened again.