I have a Windows Store app with Live Tile updates using Background Task. When I activate the app by any means (click on the live tile, switch back to the app, etc..) I want to clear the live tile (I have a number there that I want to change to zero).
To be more concerete, I run the app, I switch to another app or desktop, then I switch ti the star screen and I see a number on the Live Tile. I click the Live Tile, I am taken to the app and I want the Live Tile to clear. The same functionality as the Email app.
I tried the OnActivated method in App.xaml.cs but it does not seem to get called at any time (I put a throw new NotImplementeExeption there and the app never crashes).
You should put it in the OnLaunched method, you just need to determine where.
protected async override void OnLaunched(LaunchActivatedEventArgs args)
{
var rootFrame = new Frame();
// Do not repeat app initialization when already running, just ensure that
// the window is active
if (args.PreviousExecutionState == ApplicationExecutionState.Running)
{
//....
}
if (args.PreviousExecutionState == ApplicationExecutionState.ClosedByUser)
{
/....
}
if (!String.IsNullOrEmpty(args.Arguments))
{
//....
}
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated)
{
//....
}
if (args.PreviousExecutionState == ApplicationExecutionState.NotRunning)
{
//.....
}
TileUpdateManager.CreateTileUpdaterForApplication().Clear();
BadgeUpdateManager.CreateBadgeUpdaterForApplication().Clear();
SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;
// Create a Frame to act navigation context and navigate to the first page
if (!rootFrame.Navigate(typeof(MainPage)))
{
throw new Exception("Failed to create initial page");
}
// Place the frame in the current Window and ensure that it is active
Window.Current.Content = rootFrame;
Window.Current.Activate();
}
If you look at the code, there are several reasons of why your App is closed/suspended. So, determine in which cases you want to run de code for updating the number in the Live Tile, put it inside that if, and it should work.
I guess that the better place for such actions is the OnLaunched method. It called every time you appication start.
update: Hmm, seems you should react on both OnActivated and OnLaunched methods:
OnLaunched - Invoked when the application is launched. Override this
method to perform application initialization and to display initial
content in the associated Window.
On the application start OnLaunched will be called. But when you switch to another app and then go back OnActivated should be called:
OnActivated - Invoked when the application is activated by some means other than normal launching.
Related
I'm have just starting using XCTest for UI testing.
While running my tests, execution takes forever.
I get following output:
Wait for app to idle - waits 120 seconds to fail
App animations complete notification not received, will attempt to continue.
I have looked all over and found zero answer on how to either change the timeout or how to manipulate the app to move on.
There are no animations running at all in the app. The screen is fully loaded. My developers also have zero answers as well and I have tried disabling animations which fails the tests outright.
Any ideas on how I can address this?
func testHomeScreen() {
logIn()
let home = app.navigationBars["HOME"].staticTexts["HOME"]
waitForElementToAppear(element: home)
XCTAssert(home.exists)
let myFriendsButton = app.buttons["My Friends"]
XCTAssert(myFriendsButton.exists)
let collectionViewsQuery = app.collectionViews
collectionViewsQuery.buttons["compose"].tap()
app.navigationBars["CREATE POST"].buttons["CANCEL"].tap()
collectionViewsQuery.buttons["photo"].tap()
app.navigationBars["PHOTO BOOTH"].buttons["CANCEL"].tap()
let element = collectionViewsQuery.children(matching: .cell).element(boundBy: 1).children(matching: .other).element
element.children(matching: .other).element(boundBy: 0).children(matching: .image).element(boundBy: 0).tap()
let profileCloseButton = app.buttons["profile close"]
profileCloseButton.tap()
let image = element.children(matching: .image).element
image.swipeUp()
let button = app.navigationBars["DETAILS"].buttons[" "]
let cell = collectionViewsQuery.children(matching: .cell).element(boundBy: 0)
cell.buttons["actionsheet"].tap()
app.sheets.buttons["Cancel"].tap()
cell.buttons["comment"].tap()
button.tap()
collectionViewsQuery.buttons["like selected"].tap()
Here is my LogIn func and Setup.
func logIn() {
let app = XCUIApplication()
if app.tabBars.buttons["HOME"].exists {
logOut()
}
let logInButton = app.buttons["LOG IN"]
logInButton.tap()
let elementsQuery = app.scrollViews.otherElements
let emailField = elementsQuery.textFields["example#email.com"]
emailField.tap()
emailField.typeText("***************")
let passwordSecureTextField = elementsQuery.secureTextFields["Password"]
passwordSecureTextField.tap()
passwordSecureTextField.typeText("************")
app.navigationBars["LOG IN"].buttons["btn login"].tap()
if app.staticTexts["PLEASE TURN ON NOTIFICATIONS"].exists {
XCTAssert(app.staticTexts["This way you will be able to see when your friends post, message, like or comment on your stuff!"].exists)
app.buttons["NOT NOW"].tap()
}
if app.collectionViews.staticTexts["3D Rooms Now Available!"].exists {
XCTAssert(app.collectionViews.staticTexts["Chat with friends in 3D rooms wherever you go! Tap here to get started"].exists)
app.collectionViews.buttons["close"].tap()
}
if app.staticTexts["DAILY"].exists {
XCTAssert(app.staticTexts[" SPIN"].exists)
app.buttons["close"].tap()
}
}
Setup:
class HomeScreenTests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
continueAfterFailure = false
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
app.launch()
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
Here is a chunk of the output from the test logs:
LogFile
I figured out how to dismiss System alert, but I am not able to wait for it to show , since app doesn't see System Alerts. I tried to debug with app.debugDescription and app.alerts.count but no luck.
You should use addUIInterruptionMonitor as #Oletha wrote.
The tricky part here is that system alert buttons don't use Accessibility Identifiers so you have to search for text to tap them. This text is translated to the language you're running your simulator/device, which can be hard if you want to run the test for several languages beside English.
You could use AutoMate framework to simplify this. Here you have an example how to deal with system alerts using AutoMate:
func locationWhenInUse() {
let token = addUIInterruptionMonitor(withDescription: "Location") { (alert) -> Bool in
guard let locationAlert = LocationWhenInUseAlert(element: alert) else {
XCTFail("Cannot create LocationWhenInUseAlert object")
return false
}
locationAlert.allowElement.tap()
return true
}
// Interruption won't happen without some kind of action.
app.tap()
// Wait for given element to appear
wait(forVisibilityOf: locationPage.requestLabel)
removeUIInterruptionMonitor(token)
}
In the example above the locationAlert.allowElement.tap() is possible because AutoMate can handle any language supported by iOS Simulator.
For more examples on how to deal with system alerts using AutoMate please look into: PermissionsTests.swift
Use addUIInterruptionMonitor:withDescription:handler: to register an interruption monitor. To 'wait' for the system alert to appear, use the handler to set a variable when it has been dealt with, and execute a benign interaction with the app when you want to wait for the alert.
You must continue to interact with the app while you are waiting, as interactions are what trigger interruption monitors.
class MyTests: XCTestCase {
let app = XCUIApplication()
func testLocationAlertAppears() {
var hasDismissedLocationAlert = false
let monitor = addUIInterruptionMonitor(withDescription: "LocationPermissions") { (alert) in
// Check this alert is the location alert
let location = NSPredicate(format: "label CONTAINS 'Location'")
if alert.staticTexts.element(matching: location).exists {
// Dismiss the alert
alert.buttons["Allow"].tap()
hasDismissedLocationAlert = true
return true
}
return false
}
// Wait for location alert to be dismissed
var i = 0
while !hasDismissedLocationAlert && i < 20 {
// Do some benign interaction
app.tap()
i += 1
}
// Clean up
removeUIInterruptionMonitor(monitor)
// Check location alert was dismissed
XCTAssertTrue(hasDismissedLocationAlert)
}
}
i have run into a problem, that my app sometimes Activates and sometimes Launches when i open something via:
var options = new Windows.System.LauncherOptions();
options.DisplayApplicationPicker = false;
bool success = await Windows.System.Launcher.LaunchFileAsync(sampleFile, options);
When app re-activates it shows the same window - when i went to an external app using LaunchFileAsync - this is nice.
But sometimes the app launches, i see a SplashPage and app is beginning from the MainPage. - how can i make this also to return to the page, that i left when used LaunchFileAsync?
Example:
I have a MainPage and a BlankPage1
So here is my page on suspend+shutdown (terminate) 8 buttons:
On Restore 0 buttons, I WANT TO SAVE MY VIEW XAML CODE when app gets killed by system:
It depends entirely on the conditions of your application shutdown. Was it suspended and terminated automatically by the OS ? or did you close it yourself ? (ex : ALT-F4)
You can see here the application lifecyle : http://msdn.microsoft.com/en-us/library/windows/apps/hh464925.aspx
If you want your application to restore its previous state on a user shutdown, I think you can enable it on your OnLaunched method in you App.xaml.cs :
if (args.PreviousExecutionState == ApplicationExecutionState.Terminated
|| args.PreviousExecutionState == ApplicationExecutionState.ClosedByUser)
{
try
{
await SuspensionManager.RestoreAsync();
}
catch (SuspensionManagerException)
{
}
}
Then, if your Page extends LayoutAwarePage, you have two methods, SaveState and LoadState.
These methods are called automatically when navigating from or to the frame (including suspending/restoring/opening...).
If you save your data behind your buttons in your SaveState method, you can restore it in the LoadState method (and thus redraw your buttons). There is a detailled exemple here : http://msdn.microsoft.com/en-us/library/windows/apps/hh986968.aspx
I am using swanify's Titanium Navigation Controller https://github.com/swanify/Titanium-Navigation-Controller for my app deployed in Android device.
i am trying to pass data that i have selected from a table row here back to the previous page and populate a text field there.
Anyone has any ideas how to do it? i am looking into using events but it doesnt seem to be working for me.
thank you. :)
Here is what I have done in this situation, It makes use of the eventing aspects of JavaScript and Titanium, the general principle is to have your own custom events, fire them on a control, and listen elsewhere.
First lets say we have a file named NextWindow.js that is a CommonJS module encapsulating a window and a tableview, everytime the a row is clicked we capture that event, then fire our own custom event on the window:
function NextWindow() {
var self = Ti.UI.createWindow();
var tableView = Ti.UI.createTableView();
// Other initialization
....
....
tableView.addEventListener('click', function(e) {
// You may have to use e.rowData.title depending on how you created the table view
var rowTitle = e.row.title;
// Now fire a custom event on the window whenever a row is selected
// send the title through as data
self.fireEvent('table_row_selected', {title : rowTitle});
});
return self;
}
module.exports = NextWindow;
When you create a NextWindow to push onto the navigation stack, add a listener for a custom event to it, this is inside of the previous window with the text box:
var NextWindow = require('NextWindow');
var nextWindow = new NextWindow();
nextWindow.addEventListener('table_row_selected', function(e) {
// Do what you want here with the passed back data
var title = e.title;
some_label.text = title;
});
// Open the next window on the NavigationController stack
nav.open(nextWindow);
Now were listening for a custom event attached to the nextWindow. Say you have a TableView in your nextWindow, listen for the TableView click, and fire the custom event:
I noticed cordovaInitCallback is called each time Worklight/Cordova is initialized in an Android app. In particular, it calls Cordova's "clearHistory" to wipe out the WebView history. This has been an issue when I try to make use of window.history in a multi-page app since the history is always reset during the initializtion from page to page.
Since the comment suggests that the purpose for this clearHistory call is to prevent going back to an old page in a direct update scenario, could the condition be strengthened over an Android environment check so that it is only called if a direct update has just taken place? One case, for example, I can think of is when connectOnStartup=false, then direct update would not occur.
wlclient.js:
var cordovaInitCallback = function(returnedData) {
onEnvInit(options);
if (WL.Client.getEnvironment() == WL.Env.ANDROID) {
if (returnedData !== null && returnedData !== "") {
WL.StaticAppProps.APP_VERSION = returnedData;
}
// In development mode, the application has a settings
// widget in which the user may alter
// the application's root url
// and here the application reads this url, and replaces the
// static prop
// WL.StaticAppProps.WORKLIGHT_ROOT_URL
// __setWLServerAddress for iOS is called within
// wlgap.ios.js's wlCheckReachability
// function because it is an asynchronous call.
// Only in Android we should clear the history of the
// WebView, otherwise when user will
// press the back button after upgrade he will return to the
// html page before the upgrade
if (**WL.Env.ANDROID == getEnv()**) {
cordova.exec(null, null, 'Utils', 'clearHistory', []);
}
}
I am currently using Worklight 5.0.5, and have checked this same condition exists in 5.0.5.1.
Thanks!
The architectural design of Worklight is SPA (Single Page Application).
cordovaInitCallback should be called only once in the life cycle of the application.
That said, you can, if you wish, override it.