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:
parent
1c20a0b6d5
commit
200d1fb235
43 changed files with 2271 additions and 65 deletions
|
|
@ -2,7 +2,7 @@
|
|||
"""Reject stale Android payloads and inconsistent common release metadata."""
|
||||
|
||||
import argparse, contextlib, hashlib, io, json, re, zipfile
|
||||
from project import ROOT, release_info
|
||||
from project import ROOT, release_info, SOURCE_OVERRIDES
|
||||
|
||||
p = argparse.ArgumentParser()
|
||||
group = p.add_mutually_exclusive_group()
|
||||
|
|
@ -72,6 +72,7 @@ with source as archive:
|
|||
assert actual == expected.encode(), "Stale Android Gaia panel: " + path
|
||||
results[app + "/" + path] = hashlib.sha256(actual).hexdigest()
|
||||
for app, path, source in [
|
||||
("keyboard", "gaia_build_defer_settings.js", "overrides"),
|
||||
("calendar", "gaia_build_defer_index.js", "overrides"),
|
||||
("calendar", "js/bundle.js", "overrides"),
|
||||
("gallery", "js/metadata_scripts.js", "overrides"),
|
||||
|
|
@ -94,6 +95,13 @@ with source as archive:
|
|||
actual = gaia.read(app + "/" + path)
|
||||
assert actual == expected, "Stale application workflow: " + app + "/" + path
|
||||
results[app + "/" + path] = hashlib.sha256(actual).hexdigest()
|
||||
for app in ("keyboard", "settings"):
|
||||
for name in SOURCE_OVERRIDES[app]:
|
||||
expected = (ROOT / "gaia/apps" / app / name).read_bytes()
|
||||
if name.endswith(".js"):
|
||||
expected = translate(expected.decode()).encode()
|
||||
assert gaia.read(app + "/" + name) == expected, "Stale shared source: " + app + "/" + name
|
||||
results[app + "/" + name] = hashlib.sha256(expected).hexdigest()
|
||||
helper = "dialer/js/telephony_helper.js"
|
||||
expected = translate((ROOT / "gaia/apps/communications" / helper).read_text()).encode()
|
||||
assert gaia.read("communications/" + helper) == expected, "Stale call-log dial helper"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ SOURCE_OVERRIDES = {
|
|||
"system": ["js/launcher.js", "js/gaia_scheduler.js", "js/keyboard_manager.js",
|
||||
"js/core.js", "js/rocketbar.js"],
|
||||
"communications": ["dialer/js/telephony_helper.js"],
|
||||
"settings": ["js/modules/storage_helper.js", "js/startup.js"],
|
||||
"keyboard": ["js/settings/layout_dictionary_downloader.js"] + [
|
||||
str(path.relative_to(ROOT / "gaia/apps/keyboard"))
|
||||
for path in sorted((ROOT / "gaia/apps/keyboard/js/imes/latin/dictionaries").glob("*.dict"))
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
13
tools/refresh-keyboard.py
Normal file
13
tools/refresh-keyboard.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Refresh the dictionary loader in Gaia's packaged keyboard settings bundle."""
|
||||
from pathlib import Path
|
||||
ROOT=Path(__file__).resolve().parents[1]
|
||||
source=(ROOT/'gaia/apps/keyboard/js/settings/layout_dictionary_downloader.js').read_text()
|
||||
path=ROOT/'assets/webapps/keyboard.gaiamobile.org/gaia_build_defer_settings.js'
|
||||
bundle=path.read_text()
|
||||
start=bundle.index('(function(exports){var LayoutDictionaryDownloader=')
|
||||
end=bundle.index('exports.LayoutDictionaryDownloader=LayoutDictionaryDownloader;}(window));',start)
|
||||
end+=len('exports.LayoutDictionaryDownloader=LayoutDictionaryDownloader;}(window));')
|
||||
out=ROOT/'overrides/keyboard.gaiamobile.org/gaia_build_defer_settings.js'
|
||||
out.write_text(bundle[:start]+source+'\n'+bundle[end:])
|
||||
print(out.relative_to(ROOT))
|
||||
|
|
@ -12,6 +12,7 @@ modules = [
|
|||
('panels/wifi/wifi_network_list', 'js/panels/wifi/panel.js'),
|
||||
('modules/page_transitions', 'js/main.js'),
|
||||
('modules/settings_service', 'js/main.js'),
|
||||
('modules/panel_cache', 'js/main.js'),
|
||||
('modules/dialog_service', 'js/modules/dialog_service.js'),
|
||||
('modules/dialog_manager', 'js/modules/dialog_service.js'),
|
||||
('modules/date_time', 'js/modules/date_time.js'),
|
||||
|
|
|
|||
48
tools/test-ticket-settings.py
Normal file
48
tools/test-ticket-settings.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Regression checks for storage navigation and unavailable-feature contrast."""
|
||||
import importlib.util,json,time
|
||||
from pathlib import Path
|
||||
from marionette_client import Client
|
||||
spec=importlib.util.spec_from_file_location('probe',Path(__file__).with_name('probe-desktop.py'))
|
||||
p=importlib.util.module_from_spec(spec);spec.loader.exec_module(p)
|
||||
with Client(2857) as c:
|
||||
p.register(c)
|
||||
def ev(code):
|
||||
for _ in range(80):
|
||||
reply=p.evaluate(c,'settings',code)
|
||||
if not reply.get('missing'):break
|
||||
time.sleep(.1)
|
||||
if 'value' not in reply:raise RuntimeError(reply)
|
||||
return reply['value']
|
||||
def wait(code):
|
||||
for _ in range(80):
|
||||
if ev(code):return
|
||||
time.sleep(.1)
|
||||
raise TimeoutError(code)
|
||||
p.evaluate(c,'system','if(Service.query("locked"))await Service.request("unlock",{forcibly:true});await VulpesCompat.call("apps.launch",{manifestURL:"http://settings.localhost:8765/manifest.webapp"});return true;')
|
||||
ev('location.reload();return true;');time.sleep(.6)
|
||||
wait('return document.querySelector("section.current")?.id==="root" && require.defined("modules/settings_service");')
|
||||
for panel in ['mediaStorage','root','applicationStorage','root','usbStorage','root']:
|
||||
ev('await new Promise(resolve=>require(["modules/settings_service"],s=>s.navigate('+json.dumps(panel)+',{},resolve)));return true;')
|
||||
wait('return document.querySelector("section.current")?.id==='+json.dumps(panel)+';')
|
||||
errors=ev('return window.__vulpesDiagnostics;')
|
||||
assert not errors,errors
|
||||
# A failed dependency must not leave the navigation lock set.
|
||||
ev('const cache=require("modules/panel_cache"),get=cache.get;cache.get=function(id,cb){cache.get=get;cb(null,new Error("test dependency failure"));};await new Promise(resolve=>require("modules/settings_service").navigate("mediaStorage",{},resolve));return true;')
|
||||
time.sleep(.3)
|
||||
ev('await new Promise(resolve=>require("modules/settings_service").navigate("applicationStorage",{},resolve));return true;')
|
||||
wait('return document.querySelector("section.current")?.id==="applicationStorage";')
|
||||
ratios={}
|
||||
for theme in ['light','dark']:
|
||||
ev('document.documentElement.dataset.vulpesTheme='+json.dumps(theme)+';VulpesGaiaUI.notice("This feature is not available on this platform yet.");return true;')
|
||||
time.sleep(.2)
|
||||
colors=ev('const p=document.querySelector("#vulpes-gaia-notice p");return [getComputedStyle(p).color,getComputedStyle(p).backgroundColor];')
|
||||
def luminance(css):
|
||||
rgb=[float(v)/255 for v in css.removeprefix('rgb(').removesuffix(')').split(',')]
|
||||
linear=[v/12.92 if v<=.04045 else ((v+.055)/1.055)**2.4 for v in rgb]
|
||||
return sum(a*b for a,b in zip(linear,[.2126,.7152,.0722]))
|
||||
a,b=sorted(map(luminance,colors));ratio=(b+.05)/(a+.05);assert ratio>=4.5,(theme,colors,ratio)
|
||||
ratios[theme]=round(ratio,2)
|
||||
ev('document.querySelector("#vulpes-gaia-notice").requestSubmit();return true;')
|
||||
ev('require("modules/settings_service").navigate("root");return true;')
|
||||
print(json.dumps({'storagePanels':3,'returnNavigation':True,'failureRecovery':True,'contrast':ratios}))
|
||||
Loading…
Reference in a new issue