Skip to content

Commit 00ad8c3

Browse files
authored
Added Platform info to the result of roDeviceInfo.getModelDetails() (#414)
* Added `Platform` info to the result of `roDeviceInfo.getModelDetails()` * Replaced usage of deprecated property `navigator.platform` * Optimized code
1 parent aeb3bc9 commit 00ad8c3

File tree

12 files changed

+173
-70
lines changed

12 files changed

+173
-70
lines changed

docs/customization.md

+30-2
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,40 @@ By default, the feature `simulation_engine` is defined internally in the library
4949

5050
## App Manifest
5151

52-
There is also a way BrightScript apps can change the behavior of the simulation engine, by using custom `manifest` entries. Currently the only custom option is:
52+
There is also a way BrightScript apps can change the behavior of the simulation engine, by using special `manifest` entries. Currently the only option is:
5353

5454
- `multi_key_events=1`: If this flag is defined, will inform the simulator to handle multiple key events in parallel, instead of the default Roku behavior, that is handling one key at a time.
5555

56-
Note: custom `manifest` entries are ignored by Roku Devices.
56+
Note: this special `manifest` entry is ignored by Roku Devices.
5757

5858
## Control Mapping
5959

6060
It is also possible to customize the Remote Control mapping for the Keyboard and Game Pad, either by sending the custom mapping in the `Options` parameter when running `initialize()` method, or by using `setCustomKeys()` and `setCustomPadButtons()` later on. Check the details in the [engine API documentation](engine-api.md). To know the default mapping please check the source code at `src/api/control.ts`.
61+
62+
## Platform Details
63+
64+
The engine will also extend the results of the method `roDeviceInfo.getModelDetails()` with several attributes giving information about the platform the app is being executed:
65+
66+
```brs
67+
brs> di = createObject("roDeviceInfo")
68+
69+
brs> print di.getModelDetails()
70+
<Component: roAssociativeArray> =
71+
{
72+
Manufacturer: ""
73+
ModelNumber: "3930X"
74+
VendorName: "Roku"
75+
VendorUSBName: "Roku"
76+
inAndroid: false
77+
inBrowser: false
78+
inChromeOS: false
79+
inChromium: false
80+
inElectron: false
81+
inFirefox: false
82+
inIOS: false
83+
inLinux: false
84+
inMacOS: true
85+
inSafari: false
86+
inWindows: false
87+
}
88+
```

src/api/control.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,15 @@
55
*
66
* Licensed under the MIT License. See LICENSE in the repository root for license information.
77
*--------------------------------------------------------------------------------------------*/
8-
import { SubscribeCallback, context } from "./util";
9-
import { DataType, RemoteType, DebugCommand, keyBufferSize, keyArraySpots } from "../worker/common";
8+
import { SubscribeCallback } from "./util";
9+
import {
10+
DataType,
11+
RemoteType,
12+
DebugCommand,
13+
keyBufferSize,
14+
keyArraySpots,
15+
platform,
16+
} from "../worker/common";
1017
/// #if BROWSER
1118
import gameControl, { GCGamepad, EventName } from "esm-gamecontroller.js";
1219
/// #endif
@@ -174,7 +181,7 @@ keysMap.set("Shift+Escape", "home");
174181
keysMap.set("Control+Escape", "home");
175182
keysMap.set("Backspace", "instantreplay");
176183
keysMap.set("End", "play");
177-
if (context.inApple) {
184+
if (platform.inIOS || platform.inMacOS) {
178185
keysMap.set("Command+Backspace", "backspace");
179186
keysMap.set("Command+Enter", "play");
180187
keysMap.set("Command+ArrowLeft", "rev");

src/api/display.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* Licensed under the MIT License. See LICENSE in the repository root for license information.
77
*--------------------------------------------------------------------------------------------*/
88
import { player, subscribeVideo } from "./video";
9-
import { SubscribeCallback, context } from "./util";
9+
import { SubscribeCallback } from "./util";
10+
import { platform } from "../worker/common";
1011
import Stats from "stats.js";
1112

1213
// Simulation Display
@@ -264,7 +265,7 @@ export function showDisplay() {
264265
// Clear Display and Buffer
265266
export function clearDisplay() {
266267
window.cancelAnimationFrame(lastFrameReq);
267-
if (ctx && context.inSafari) {
268+
if (ctx && platform.inSafari) {
268269
ctx.fillStyle = "black";
269270
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
270271
} else if (ctx) {

src/api/index.ts

+7-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Licensed under the MIT License. See LICENSE in the repository root for license information.
77
*--------------------------------------------------------------------------------------------*/
8-
import { SubscribeCallback, getNow, getWorkerLibPath, context, saveDataBuffer } from "./util";
8+
import { SubscribeCallback, getNow, getWorkerLibPath, saveDataBuffer } from "./util";
99

1010
import {
1111
AppExitReason,
@@ -19,6 +19,7 @@ import {
1919
getExitReason,
2020
isAppData,
2121
isNDKStart,
22+
platform,
2223
} from "../worker/common";
2324

2425
import {
@@ -113,7 +114,7 @@ export function initialize(customDeviceInfo?: Partial<DeviceInfo>, options: any
113114
"videoFormats",
114115
"fonts",
115116
"password",
116-
"runContext",
117+
"platform",
117118
];
118119
invalidKeys.forEach((key) => {
119120
if (key in customDeviceInfo) {
@@ -474,7 +475,7 @@ function workerCallback(event: MessageEvent) {
474475
updateBuffer(event.data);
475476
} else if (event.data instanceof Map) {
476477
deviceData.registry = event.data;
477-
if (context.inBrowser) {
478+
if (platform.inBrowser) {
478479
const storage: Storage = window.localStorage;
479480
deviceData.registry.forEach(function (value: string, key: string) {
480481
storage.setItem(key, value);
@@ -483,13 +484,13 @@ function workerCallback(event: MessageEvent) {
483484
notifyAll("registry", event.data);
484485
} else if (event.data instanceof Array) {
485486
addSoundPlaylist(event.data);
486-
} else if (event.data.audioPath && context.inBrowser) {
487+
} else if (event.data.audioPath && platform.inBrowser) {
487488
addSound(event.data.audioPath, event.data.audioFormat, new Blob([event.data.audioData]));
488-
} else if (event.data.videoPlaylist && context.inBrowser) {
489+
} else if (event.data.videoPlaylist && platform.inBrowser) {
489490
if (event.data.videoPlaylist instanceof Array) {
490491
addVideoPlaylist(event.data.videoPlaylist);
491492
}
492-
} else if (event.data.videoPath && context.inBrowser) {
493+
} else if (event.data.videoPath && platform.inBrowser) {
493494
addVideo(event.data.videoPath, new Blob([event.data.videoData], { type: "video/mp4" }));
494495
} else if (isAppData(event.data)) {
495496
notifyAll("launch", { app: event.data.id, params: event.data.params ?? new Map() });

src/api/package.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Licensed under the MIT License. See LICENSE in the repository root for license information.
77
*--------------------------------------------------------------------------------------------*/
88
import { drawSplashScreen, clearDisplay, drawIconAsSplash } from "./display";
9-
import { bufferToBase64, parseCSV, SubscribeCallback, context } from "./util";
9+
import { bufferToBase64, parseCSV, SubscribeCallback } from "./util";
1010
import { unzipSync, zipSync, strFromU8, strToU8, Zippable, Unzipped } from "fflate";
1111
import { addSound, audioCodecs } from "./sound";
1212
import { addVideo, videoFormats } from "./video";
@@ -20,6 +20,7 @@ import {
2020
AppData,
2121
AppExitReason,
2222
DeviceInfo,
23+
platform,
2324
} from "../worker/common";
2425
import models from "../worker/libraries/common/models.csv";
2526
import packageInfo from "../../package.json";
@@ -29,7 +30,6 @@ export const deviceData: DeviceInfo = Object.assign(defaultDeviceInfo, {
2930
models: parseCSV(models),
3031
audioCodecs: audioCodecs(),
3132
videoFormats: videoFormats(),
32-
runContext: context,
3333
});
3434

3535
// App Data
@@ -114,9 +114,9 @@ function processFile(relativePath: string, fileData: Uint8Array) {
114114
paths.push({ id: 0, url: relativePath, type: "pcode" });
115115
} else if (lcasePath === "source/var") {
116116
paths.push({ id: 1, url: relativePath, type: "pcode" });
117-
} else if (context.inBrowser && audioExt.has(ext)) {
117+
} else if (platform.inBrowser && audioExt.has(ext)) {
118118
addSound(`pkg:/${relativePath}`, ext, new Blob([fileData]));
119-
} else if (context.inBrowser && videoExt.has(ext)) {
119+
} else if (platform.inBrowser && videoExt.has(ext)) {
120120
addVideo(`pkg:/${relativePath}`, new Blob([fileData], { type: "video/mp4" }));
121121
}
122122
}
@@ -148,7 +148,7 @@ function processManifest(content: string): number {
148148
if (icon?.slice(0, 5) === "pkg:/") {
149149
iconFile = currentZip[icon.slice(5)];
150150
if (iconFile) {
151-
if (context.inBrowser) {
151+
if (platform.inBrowser) {
152152
bufferToBase64(iconFile).then(function (iconBase64: string) {
153153
notifyAll("icon", iconBase64);
154154
});

src/api/util.ts

+1-37
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*
66
* Licensed under the MIT License. See LICENSE in the repository root for license information.
77
*--------------------------------------------------------------------------------------------*/
8-
import { RunContext, dataBufferIndex, dataBufferSize } from "../worker/common";
8+
import { dataBufferIndex, dataBufferSize } from "../worker/common";
99
import packageInfo from "../../package.json";
1010

1111
// Module callback function definition
@@ -37,42 +37,6 @@ export function getWorkerLibPath(): string {
3737
return libPath;
3838
}
3939

40-
// Check the context where the library is running
41-
export const context = getContext();
42-
function getContext(): RunContext {
43-
let inElectron = false;
44-
let inChromium = false;
45-
let inBrowser = false;
46-
let inSafari = false;
47-
let inApple = false;
48-
let inIOS = false;
49-
if (typeof window !== "undefined") {
50-
inBrowser = true;
51-
inChromium =
52-
("chrome" in window || (window.Intl && "v8BreakIterator" in Intl)) && "CSS" in window;
53-
}
54-
if (typeof navigator !== "undefined" && typeof navigator.userAgent === "string") {
55-
inElectron = navigator.userAgent.indexOf("Electron") >= 0;
56-
inApple = /(Mac|iPhone|iPad|iPod)/i.test(navigator.platform);
57-
inSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
58-
inIOS =
59-
/iPad|iPhone|iPod/.test(navigator.platform) ||
60-
(typeof navigator.maxTouchPoints !== "undefined" &&
61-
navigator.maxTouchPoints > 2 &&
62-
/MacIntel/.test(navigator.platform));
63-
} else {
64-
inApple = process.platform === "darwin";
65-
}
66-
return {
67-
inElectron: inElectron,
68-
inChromium: inChromium,
69-
inBrowser: inBrowser,
70-
inSafari: inSafari,
71-
inApple: inApple,
72-
inIOS: inIOS,
73-
};
74-
}
75-
7640
export function saveDataBuffer(sharedArray: Int32Array, data: string) {
7741
// Store string on SharedArrayBuffer
7842
data = data.trim();

src/api/video.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
*
66
* Licensed under the MIT License. See LICENSE in the repository root for license information.
77
*--------------------------------------------------------------------------------------------*/
8-
import { SubscribeCallback, context, saveDataBuffer } from "./util";
9-
import { BufferType, DataType, MediaEvent } from "../worker/common";
8+
import { SubscribeCallback, saveDataBuffer } from "./util";
9+
import { BufferType, DataType, MediaEvent, platform } from "../worker/common";
1010
import Hls from "hls.js";
1111

1212
// Video Objects
@@ -172,7 +172,7 @@ export function switchVideoState(play: boolean) {
172172
export function videoFormats() {
173173
const codecs: string[] = [];
174174
const containers: string[] = [];
175-
if (context.inBrowser) {
175+
if (platform.inBrowser) {
176176
// Mime and Codecs browser test page
177177
// https://cconcolato.github.io/media-mime-support/
178178
const formats = new Map([
@@ -198,7 +198,7 @@ export function videoFormats() {
198198
if (player.canPlayType("video/mp2t") !== "") {
199199
containers.push("ts");
200200
}
201-
if (context.inChromium) {
201+
if (platform.inChromium) {
202202
containers.push("mkv");
203203
}
204204
}

src/worker/brsTypes/components/RoDeviceInfo.ts

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Callable, StdlibArgument } from "../Callable";
55
import { Interpreter } from "../../interpreter";
66
import { RoAssociativeArray, AAMember } from "./RoAssociativeArray";
77
import { RoArray } from "./RoArray";
8+
import { isPlatform } from "../../common";
89
import { v4 as uuidv4 } from "uuid";
910
import * as crypto from "crypto";
1011
/// #if !BROWSER
@@ -167,7 +168,12 @@ export class RoDeviceInfo extends BrsComponent implements BrsValue {
167168
});
168169
result.push({ name: new BrsString("VendorName"), value: new BrsString("Roku") });
169170
result.push({ name: new BrsString("VendorUSBName"), value: new BrsString("Roku") });
170-
// TODO: Add the engine host platform info here
171+
const platform = interpreter.deviceInfo.get("platform");
172+
if (isPlatform(platform)) {
173+
for (const [key, value] of Object.entries(platform)) {
174+
result.push({ name: new BrsString(key), value: BrsBoolean.from(value) });
175+
}
176+
}
171177
return new RoAssociativeArray(result);
172178
},
173179
});

0 commit comments

Comments
 (0)