How to save an image in Windows Phone 8.1 using WinJS - javascript

I am looking to migrate my Windows 8 app to Windows Phone 8.1 using WinJS. I had used picker.pickSaveFileAsync in Windows 8 which is not supported for WP 8.1.
I had then referred the official samples from http://code.msdn.microsoft.com/windowsapps/Simple-Imaging-Sample-a2dec2b0
The Javascript version in the sample does not save on Windows Phone 8.1 when the Save As button is clicked and it returns the below error when `getFileAsync is called:
0x80004005 - JavaScript runtime error: Unspecified error
When clicked on Save, it returns a Read Only error. I had tested the sample in Lumia 520 also. I get the same error in the phone.

In Windows Phone you cannot get write access to files returned from a FileOpenPicker. You have to use a FileSavePicker to do this. With the help of a coworker I was able to get a sample working that can open and then re-save a file under a new name starting from the "Blank" Windows Phone App template
Inside of your default.html create two buttons:
<button id="choose">Choose a Photo</button>
<button id="save">Save a Photo</button>
Replace default.js with the following:
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
var origFile = null;
function pickPhoto() {
var picker = new Windows.Storage.Pickers.FileOpenPicker();
var enumerator = Windows.Graphics.Imaging.BitmapDecoder.getDecoderInformationEnumerator();
enumerator.forEach(function (decoderInfo) {
decoderInfo.fileExtensions.forEach(function (fileExtension) {
picker.fileTypeFilter.append(fileExtension);
});
});
picker.pickSingleFileAndContinue();
}
function loadPhoto(file) {
origFile = file;
}
function savePhotoPicker(file) {
var picker = new Windows.Storage.Pickers.FileSavePicker();
picker.fileTypeChoices.insert("JPEG file", [".jpg"]);
picker.pickSaveFileAndContinue();
}
function savePhoto(src, dest) {
src.copyAndReplaceAsync(dest).done(function () {
console.log("success");
})
}
app.onactivated = function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
args.setPromise(WinJS.UI.processAll());
document.getElementById("choose").addEventListener("click", pickPhoto);
document.getElementById("save").addEventListener("click", savePhotoPicker);
}
if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.pickFileContinuation) {
loadPhoto(args.detail.files[0]);
}
if (args.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.pickSaveFileContinuation) {
savePhoto(origFile, args.detail.file);
}
};
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. You might use the
// WinJS.Application.sessionState object, which is automatically
// saved and restored across suspension. If you need to complete an
// asynchronous operation before your application is suspended, call
// args.setPromise().
};
app.start();
})();
If you are creating the file yourself, make sure to set the ImageProperties for it before saving.
Sorry about the broken sample, I'll get that reported to the sample owner.

Related

What should I do with the redundant state of a ServiceWorker?

I gotta a companion script for a serviceworker and I'm trialling right now.
The script works like so:
((n, d) => {
if (!(n.serviceWorker && (typeof Cache !== 'undefined' && Cache.prototype.addAll))) return;
n.serviceWorker.register('/serviceworker.js', { scope: './book/' })
.then(function(reg) {
if (!n.serviceWorker.controller) return;
reg.onupdatefound = () => {
let installingWorker = reg.installing;
installingWorker.onstatechange = () => {
switch (installingWorker.state) {
case 'installed':
if (navigator.serviceWorker.controller) {
updateReady(reg.waiting);
} else {
// This is the initial serviceworker…
console.log('May be skipwaiting here?');
}
break;
case 'waiting':
updateReady(reg.waiting);
break;
case 'redundant':
// Something went wrong?
console.log('[Companion] new SW could not install…')
break;
}
};
};
}).catch((err) => {
//console.log('[Companion] Something went wrong…', err);
});
function updateReady(worker) {
d.getElementById('swNotifier').classList.remove('hidden');
λ('refreshServiceWorkerButton').on('click', function(event) {
event.preventDefault();
worker.postMessage({ 'refreshServiceWorker': true } );
});
λ('cancelRefresh').on('click', function(event) {
event.preventDefault();
d.getElementById('swNotifier').classList.add('hidden');
});
}
function λ(selector) {
let self = {};
self.selector = selector;
self.element = d.getElementById(self.selector);
self.on = function(type, callback) {
self.element['on' + type] = callback;
};
return self;
}
let refreshing;
n.serviceWorker.addEventListener('controllerchange', function() {
if (refreshing) return;
window.location.reload();
refreshing = true;
});
})(navigator, document);
I'm a bit overwhelmed right now by the enormity of the service workers api and unable to "see" what one would do with reg.installing returning a redundant state?
Apologies if this seems like a dumb question but I'm new to serviceworkers.
It's kinda difficult to work out what your intent is here so I'll try and answer the question generally.
A service worker will become redundant if it fails to install or if it's superseded by a newer service worker.
What you do when this happens is up to you. What do you want to do in these cases?
Based on the definition here https://www.w3.org/TR/service-workers/#service-worker-state-attribute I am guessing just print a log in case it comes up in debugging otherwise do nothing.
You should remove any UI prompts you created that ask the user to do something in order to activate the latest service worker. And be patient a little longer.
You have 3 service workers, as you can see on the registration:
active: the one that is running
waiting: the one that was downloaded, and is ready to become active
installing: the one that we just found, being downloaded, after which it becomes waiting
When a service worker reaches #2, you may display a prompt to the user about the new version of the app being just a click away. Let's say they don't act on it.
Then you publish a new version. Your app detects the new version, and starts to download it. At this point, you have 3 service workers. The one at #2 changes to redundant. The one at #3 is not ready yet. You should remove that prompt.
Once #3 is downloaded, it takes the place of #2, and you can show that prompt again.
Write catch function to see the error. It could be SSL issue.
/* In main.js */
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js')
.then(function(registration) {
console.log("Service Worker Registered", registration);
})
.catch(function(err) {
console.log("Service Worker Failed to Register", err);
})
}

WinRT - Starting/Registering IBackgroundTask in universal application

I would like to start my IBackgroundTask when my application starts up.
I have added my task to the .appxmanifest.xml file, and my extensions tag now looks like this
<Extensions>
<Extension Category="windows.backgroundTasks" EntryPoint="CordovaApp.Library.UploadTask">
<BackgroundTasks>
<Task Type="systemEvent" />
<Task Type="timer" />
</BackgroundTasks>
</Extension>
</Extensions>
My IBackgroundTask class is called UploadTask and is held in another project which has the outtype set to Windows Runtime Component.
Here is a cut down version of the code, so you can see the namespace etc
namespace CordovaApp.Library
{
public sealed class UploadTask : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
var connectionProfile = NetworkInformation.GetInternetConnectionProfile();
// connectionProfile can be null (e.g. airplane mode)
if (connectionProfile != null && connectionProfile.IsWlanConnectionProfile)
{
// custom code here
}
}
}
}
I have added a reference to this project to my universal runtime component project.
Everything builds fine.
Now to start the application, i guess i have to use WinJs, so i have the following code.
var uploadTaskName = 'UploadTask';
var tasks = Windows.ApplicationModel.Background.BackgroundTaskRegistration.allTasks;
var uploadTaskFound = false;
for (var i = 0; i < tasks.length; i++) {
if (tasks[i].Value.name == uploadTaskName) {
successCallback();
return;
}
}
Windows.ApplicationModel.Background.BackgroundExecutionManager.requestAccessAsync().then(function() {
var builder = new Windows.ApplicationModel.Background.BackgroundTaskBuilder();
builder.name = "Upload Task";
builder.taskEntryPoint = "CordovaApp.Library.UploadTask";
builder.setTrigger(new Windows.ApplicationModel.Background.TimeTrigger(15, false));
return builder.register();
}).done(function () {
successCallback();
}, function(err) {
errorCallback(err);
});
Now the requestAccessAsync method always throws an exception of
0x80004005 - JavaScript runtime error: Unspecified error
WinRT information: The application is not lock-screen capable.
Have a registered everything correctly? I am running this via Visual Studio 2013 on a laptop.
Seems that because the app was already installed, the permission was not given.
By uninstalling the application, and re-running it, i was then prompted to allow/disallow the background service to run. Checked allow, and now seems to work

Access to files from extension return sometimes NS_ERROR_FILE_IS_LOCKED

Our extension (Addon SDK) looking for new files in folder C:\scan and send it to server. Every second extension look for latest file creation time and defined it as latest.(compare new file creation time and file creation time 1 sec ago.)
Files put to C:\scan from scanner Brother 7050 on Windows 7.
But sometimes into console.error we see:
Exception
message: "Component returned failure code: 0x8052000e (NS_ERROR_FILE_IS_LOCKED)
[nsIFileInputStream.init]",
result: 2152857614,
name: "NS_ERROR_FILE_IS_LOCKED"
I think Brother 7050 application have no time to unlock file before our extension can start to read it.
Q: How we can read latest file in folder true way without read file lock error?
/*
adr- folder path
array2 - array for search
mode - search or not search in array2 (0-1)
*/
function getfilelist(adr,array2, mode)
{
filelist2=[];
filelist2[0]="";
filelist2[1]=0;
var file = new FileUtils.File(adr);
var enumerator = file.directoryEntries;
while (enumerator.hasMoreElements())
{
inner = enumerator.getNext().QueryInterface(Ci.nsIFile);
if (inner.isFile())
{
namearray=inner.leafName.split(".");
r=namearray[namearray.length-1];
if (r=="jpg" || r=="jpeg")
{
if (mode==0)
{
if (inner.lastModifiedTime>filelist2[1])
{
filelist2[0]=inner.leafName;
filelist2[1]=inner.lastModifiedTime;
}
}
else if (mode==1)
{
if (inner.lastModifiedTime>array2[1] && inner.isReadable()==true)
return inner.leafName;
}
}
}
}
if (mode==0)
{
return filelist2;
}
return false;
}
The reason why you see NS_ERROR_FILE_IS_LOCKED is most likely that the file is still being written and you are trying to access it too early. However, it is also possible that some other software immediately locks the file to check it, e.g. your anti-virus.
Either way, there is no way to ignore the lock. Even if you could, you might get an incomplete file as a result. What you should do is noting that exception and remembering that you should try to read that file on next run. Something along these lines:
var {Cr} = require("chrome");
var unaccessible = null;
setInterval(checknewfiles, 1000);
function checknewfiles()
{
var files = getfilelist(...);
if (unaccessible)
{
// Add any files that we failed to read before to the end of the list
files.push.apply(files, unaccessible);
unaccessible = null;
}
for (var file of files)
{
try
{
readfile(file);
}
except(e if e.result == Cr.NS_ERROR_FILE_IS_LOCKED)
{
if (!unaccessible)
unaccessible = [];
unaccessible.push(file);
}
}
}
For reference:
Components.results
Chrome authority
Conditional catch clauses
for..of loop

0x800a1391 - JavaScript runtime error: 'Application' is undefined

I was following the "HelloWorldWithPages" tutorial from
0x800a1391 - JavaScript runtime error: 'Application' is undefined
It occurs right here: return nav.navigate(Application.navigator.home);
Here is the full file:
default.js
// For an introduction to the Navigation template, see the following documentation:
// http://go.microsoft.com/fwlink/?LinkId=232506
(function () {
"use strict";
var app = WinJS.Application;
var activation = Windows.ApplicationModel.Activation;
var nav = WinJS.Navigation;
app.addEventListener("activated", function (args) {
if (args.detail.kind === activation.ActivationKind.launch) {
if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
// TODO: This application has been newly launched. Initialize
// your application here.
} else {
// TODO: This application has been reactivated from suspension.
// Restore application state here.
}
// Save the previous execution state.
WinJS.Application.sessionState.previousExecutionState =
args.detail.previousExecutionState;
if (app.sessionState.history) {
nav.history = app.sessionState.history;
}
args.setPromise(WinJS.UI.processAll().then(function () {
if (nav.location) {
nav.history.current.initialPlaceholder = true;
return nav.navigate(nav.location, nav.state);
} else {
return nav.navigate(Application.navigator.home);
}
}));
}
});
app.oncheckpoint = function (args) {
// TODO: This application is about to be suspended. Save any state
// that needs to persist across suspensions here. If you need to
// complete an asynchronous operation before your application is
// suspended, call args.setPromise().
app.sessionState.history = nav.history;
};
app.start();
})();
Please let me know if I need to show the code from any other file too. I am unable to understand why this problem keeps coming.

BreezeJs with dedicated web worker

I am trying to initialize a Breeze manager inside a 'Web Worker'.
RequireJs, knockout, q, breeze are being imported inside the worker.
After a call to:EntityQuery.from('name').using(manager).execute(),
the following error appears:
Uncaught Error: Q is undefined. Are you missing Q.js? See https://github.com/kriskowal/q.
A live preview is uploaded here http://plnkr.co/edit/meXjKa?p=preview
(plunk supports downloading for easier debug).
EDIT -- relevant code
Worker.js
importScripts('knockout.js', 'q.js', 'breeze.js', 'require.js');
define('jquery', function () { return jQuery; });
define('knockout', ko);
define('q', Q); //Just trying to assign q since breeze requests Q as q
require(function () {
var self = this;
this.q = this.Q; //Just trying to assign q since breeze requests Q as q
breeze.NamingConvention.camelCase.setAsDefault();
var manager = new breeze.EntityManager("breeze/Breeze");
var EntityQuery = breeze.EntityQuery;
// Q or q here is defined (TESTED)
var test = function (name) {
return EntityQuery.from(name)
.using(manager).execute() // <-- Here q/Q breaks (I think on execute)
};
var primeData = function () {
return test('Languages')
.then(test('Lala'))
.then(test('Lala2'))
};
primeData();
setTimeout(function () { postMessage("TestMan"); }, 500);
});
Worker will be initialized on main page as:
var myWorker = new Worker("worker.js");
Ok here it goes:
Create a new requireJs and edit the
isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document)
to
isBrowser = false
Create a new Jquery so it uses nothing related to window and generally anything that a WebWorker cannot access. Unfortunatelly i can't remember where i got this Custom JQueryJs but i have uploaded it here "https://dl.dropboxusercontent.com/u/48132252/jqueydemo.js".
Please if you find the author or the original change link and give credit.
My workerJs file looks like:
importScripts('Scripts/test.js', 'Scripts/jqueydemo.js', 'Scripts/q.js', 'Scripts/breeze.debug.js', 'Scripts/require2.js');
define('jquery', function () { return jQuery; });
require(
{
baseUrl: "..",
},
function () {
var manager = new breeze.EntityManager("breeze/Breeze");
var EntityQuery = breeze.EntityQuery;
var primeData = function () {
return EntityQuery.from(name)
.using(manager).execute() // Get my Data
.then(function (data) {
console.log("fetced!\n" + ((new Date()).getTime()));
var exportData = manager.exportEntities(); // Export my constructed entities
console.log("created!\n" + ((new Date()).getTime()));
var lala = JSON.stringify(exportData)
postMessage(lala); // Send them as a string to the main thread
})
};
primeData();
});
Finally on my mainJs i have something like:
this.testWorker = function () {
var myWorker = new Worker("worker.js"); // Init Worker
myWorker.onmessage = function (oEvent) { // On worker job finished
toastr.success('Worker finished and returned');
var lala = JSON.parse(oEvent.data); // Reverse string to JSON
manager.importEntities(lala); // Import the pre-Constructed Entities to breezeManager
toastr.success('Import done');
myWorker.terminate();
};
};
So we have managed to use breeze on a WebWorker enviroment to fetch and create all of our entities, pass our exported entities to our main breeze manager on the main thread(import).
I have tested this with 9 tables fully related to each other and about 4MB of raw data.
PROFIT: UI stays fully responsive all the time.
No more long execution script, application not responding or out of memory errors) at least for chrome
*As it makes sense breeze import entities is way more faster than the creation a full 4MB raw data plus the association process following for these entities.
By having all the heavy work done on the back, and only use import entities on the front, breeze allows you to handle large datasets 'like a breeze'.

Categories

Resources