Release Android Preview 21 and bilingual changelog

Add permission-based reading of Android contacts, SMS and call history. Include shared Gaia fixes and document device validation limits. Pixel image qualification remains pending.
This commit is contained in:
OverSu 2026-10-14 13:13:46 +02:00
commit 200d1fb235
43 changed files with 2271 additions and 65 deletions

View file

@ -0,0 +1,34 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import vm from 'node:vm';
import {readFileSync} from 'node:fs';
const source=readFileSync(new URL('../gaia/apps/marketplace/marketplace.js',import.meta.url),'utf8');
function element(){return Object.assign(new EventTarget(),{style:{},hidden:false,textContent:''});}
async function setup() {
const nodes=Object.fromEntries(['catalogue','message','confirm','open','browse','install','cancel','status','title','question','permissions'].map(id=>[id,element()]));
let poll,download=null,finish;
const context={document:{getElementById:id=>nodes[id]},navigator:{language:'en'},console,
addEventListener(){},setInterval:fn=>poll=fn,VulpesCompat:{call:async method=>{
if(method==='locale.current')return 'en';
if(method==='marketplace.poll'){const url=download;download=null;return url;}
if(method==='marketplace.prepare')return new Promise(resolve=>finish=resolve);
}}};
await vm.runInNewContext(source,context);
return {nodes,poll,setDownload:()=>download='https://vulpes-os.org/marketplace/index.php?download=1',finish:()=>finish({name:'Test',bytes:1024,token:'test'})};
}
test('closing the Android web view exposes a way back to the catalogue, not a blank frame',async()=>{
const {nodes:n}=await setup();
n.catalogue.dispatchEvent(new Event('mozbrowserclose'));
assert.equal(n.message.hidden,false);assert.equal(n.catalogue.style.visibility,'hidden');
assert.match(n.status.textContent,/reopen/);assert.equal(n.open.hidden,true);
n.browse.onclick();
assert.equal(n.message.hidden,true);assert.equal(n.catalogue.style.visibility,'visible');
assert.match(n.catalogue.src,/mode=app&lang=en/);
});
test('a close notification cannot erase an installation confirmation',async()=>{
const f=await setup();f.setDownload();const pending=f.poll();
await new Promise(resolve=>setImmediate(resolve));
f.nodes.catalogue.dispatchEvent(new Event('mozbrowserclose'));
assert.match(f.nodes.status.textContent,/Checking/);
f.finish();await pending;assert.equal(f.nodes.confirm.hidden,false);
});