Fix camera switching and Contacts/SMS activity routing across shared hosts. Integrate Marketplace installation and native standalone recovery tools, Bluetooth runtime packages and trusted certificates. Update English/French READMEs and the shared changelog with tested scope and remaining radio/audio/Bluetooth limitations. Preview17 remains the existing APK; no new native image is released. Validation: shared JavaScript and native Python tests; Android packaging and payload parity from an isolated publication checkout.
41 lines
1.7 KiB
JavaScript
41 lines
1.7 KiB
JavaScript
// Settings persistence and Android RPC use JSON. Preserve binary Gaia values across
|
|
// both boundaries and reconstruct Blobs in the application's own JS realm.
|
|
(() => {
|
|
const marker = '__vulpesBlobV1';
|
|
async function encode(value) {
|
|
if (value instanceof Date) return value.toJSON();
|
|
if (value instanceof Blob) {
|
|
if (value.size > 16 * 1024 * 1024) throw new Error('SETTING_BLOB_TOO_LARGE');
|
|
const bytes = new Uint8Array(await value.arrayBuffer());
|
|
const chunks = [];
|
|
for (let i = 0; i < bytes.length; i += 16384) {
|
|
chunks.push(String.fromCharCode(...bytes.subarray(i, i + 16384)));
|
|
}
|
|
return { [marker]: true, type: value.type, base64: btoa(chunks.join('')) };
|
|
}
|
|
if (Array.isArray(value)) return Promise.all(value.map(encode));
|
|
if (value && typeof value === 'object') {
|
|
return Object.fromEntries(
|
|
await Promise.all(
|
|
Object.entries(value).map(async ([key, item]) => [key, await encode(item)]),
|
|
),
|
|
);
|
|
}
|
|
return value;
|
|
}
|
|
function decode(value) {
|
|
if (!value || typeof value !== 'object' || value instanceof Blob || value instanceof Date) return value;
|
|
if (
|
|
value[marker] === true &&
|
|
typeof value.type === 'string' &&
|
|
typeof value.base64 === 'string' &&
|
|
Object.keys(value).length === 3
|
|
) {
|
|
const bytes = Uint8Array.from(atob(value.base64), (c) => c.charCodeAt(0));
|
|
return new Blob([bytes], { type: value.type });
|
|
}
|
|
if (Array.isArray(value)) return value.map(decode);
|
|
return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, decode(item)]));
|
|
}
|
|
window.VulpesSettingsCodec = Object.freeze({ encode, decode });
|
|
})();
|