Device & Resolution
Hosanna exposes a device abstraction that reports resolution, quality, layout expression, orientation, DPI, and host screen metrics. Use this facade when shared app code needs device information; avoid direct window, user-agent, or native checks inside views.
For the broader platform vocabulary and capability model, see Cross-Platform Runtime Model. For web launch parameters, see Web Expression, DPI, and Touch Input.
Platform-Neutral Device Facade
IHosannaDevice provides cross-platform access to device services and normalized metrics:
export interface IHosannaDevice {
configure(): unknown;
onSystemDeviceInfoEvent(event: ISystemEvent<JsonData>): unknown;
deviceInfo: ISGRODeviceInfo;
deviceRegistry: IDeviceRegistry;
appInfo: ISGROAppInfo;
resolutionInfo: IResolutionInfo;
deviceQuality: DeviceQuality;
expression: Expression;
deviceLayoutOrientation: DeviceLayoutOrientation;
deviceDpi: number;
devicePreset?: string;
screenInfo: IHosannaScreenInfo;
layoutInfo: IHosannaDeviceLayoutInfo;
getScreenInfo(): IHosannaScreenInfo;
}
- deviceRegistry: Platform-neutral key-value storage for tokens, flags, and lightweight settings.
- deviceInfo: Low-level device information, including UI resolution and model details where the target supports them.
- appInfo: Metadata about the running app/build.
- resolutionInfo: Normalized resource-resolution details.
- deviceQuality: Coarse performance/quality tier.
- expression: Active app/layout expression:
tv,web,phone, ortablet. - deviceLayoutOrientation: Active design-surface orientation:
portraitorlandscape. - deviceDpi: Physical pixel width for the active design surface.
- devicePreset: Optional preset name that supplied web/bootstrap metrics.
- screenInfo: Raw host viewport, screen, DPR, and safe-area metrics.
- layoutInfo: Shared, view-facing layout model with derived flags, padding, and content bounds.
Device Layout Info
Views should use deviceLayout for fast layout decisions. It is a stable object registered in IoC by the platform initializer and injected into HosannaDevice as layoutInfo. Reads are plain field reads; no getter or snapshot call is needed.
import { inject } from '@hs-src/hosanna-bridge-core/decorators';
import type { IHosannaDeviceLayoutInfo } from '@hs-src/hosanna-bridge-core/api';
export class MyView extends BaseView<MyState> {
@inject() protected deviceLayout!: IHosannaDeviceLayoutInfo;
protected override getViews() {
const width = this.deviceLayout.contentWidth;
const top = this.deviceLayout.topPadding;
// ...
}
}
hosannaDevice.layoutInfo and @inject() deviceLayout are the same object. Runtime metric changes mutate the object in place and increment revision only when exposed layout fields change.
Common fields include:
mode,expression,orientation, and flags such asisTv,isPhone,isTablet,isPortrait, andisLandscape.designWidth/designHeightfor the active Hosanna design surface.viewportWidth/viewportHeight,hostScreenWidth/hostScreenHeight,devicePixelRatio, anddpi.safeAreaTop,safeAreaRight,safeAreaBottom,safeAreaLeft.horizontalPadding,verticalPadding,topPadding,bottomPadding.contentX,contentY,contentWidth,contentHeight, andcontentBottomInset.
Use screenInfo only when code needs the raw host measurement contract. Use deviceLayout for view layout, responsive branching, safe-area-aware content bounds, and fragment-style calculations.
ScreenInfo
screenInfo is distinct from the Hosanna design surface. It describes the actual browser, WebView, or native host viewport.
export interface IHosannaScreenInfo {
viewportWidth: number;
viewportHeight: number;
screenWidth: number;
screenHeight: number;
devicePixelRatio: number;
safeAreaInsets: {
top: number;
right: number;
bottom: number;
left: number;
};
}
safeAreaInsets protects drawing and interaction from system bars, display cutouts, and rounded edges.
On Web and Capacitor, the web device reads browser/WebView metrics and CSS env(safe-area-inset-*) values. UIKit and Android WindowInsetsCompat feed native values through the same interface. Hosanna converts them to design points; app code should not maintain device-specific notch tables. screenInfo intentionally does not include derived layout flags or content helpers; those live on deviceLayout.
See Safe Areas and Edge-to-Edge Screens for contained, background-bleed, hero-bleed, and full-viewport collection patterns.
IResolutionInfo
export interface IResolutionInfo {
suffix: string;
scale: number;
width: number;
height: number;
}
- suffix: Resolution suffix such as
fhd,hd, orsd. - scale: Pixel scale relative to FHD.
- width / height: UI resolution in pixels.
BaseHosannaDevice
BaseHosannaDevice resolves UI resolution, quality, expression, orientation, DPI, and screen metrics during configure(). You can override quality with the debug flag device.forcedDeviceQuality, using DeviceQuality.Low, DeviceQuality.Medium, or DeviceQuality.High.
export class BaseHosannaDevice implements IHosannaDevice {
appInfo: ISGROAppInfo = CreateObject('roAppInfo');
deviceInfo: ISGRODeviceInfo = CreateObject('roDeviceInfo');
deviceQuality: DeviceQuality = DeviceQuality.High;
expression: Expression = Expression.TV;
deviceLayoutOrientation: DeviceLayoutOrientation = DeviceLayoutOrientation.Landscape;
deviceDpi = 1920;
resolutionInfo: IResolutionInfo = {
suffix: 'fhd',
scale: 1.0,
width: 1920,
height: 1080,
};
screenInfo: IHosannaScreenInfo = {
viewportWidth: 1920,
viewportHeight: 1080,
screenWidth: 1920,
screenHeight: 1080,
devicePixelRatio: 1,
safeAreaInsets: { top: 0, right: 0, bottom: 0, left: 0 },
};
@inject('deviceLayout') layoutInfo!: IHosannaDeviceLayoutInfo;
configure(): void {
this.resolutionInfo = this.getUIResolutionInfo();
this.applyDesignResolutionOverridesFromGlobalAa();
this.deviceDpi = this.getDeviceDpi();
this.devicePreset = this.getDevicePreset();
syncHosannaDeviceScreenInfo(this);
syncHosannaDeviceLayoutInfo(this);
this.deviceQuality = this.getDeviceQuality();
this.configurePlaybackInfo();
this.configureDRMSupportInfo();
}
}
The excerpt shows the configuration sequence, not every field, injection, or helper on the concrete class. Platform subclasses provide host metrics through getScreenInfo(). The synchronization helpers mutate the shared screenInfo and layoutInfo objects in place so injected references stay valid.
Inject device.forcedDeviceQuality to simulate lower-end devices and verify fallback styling, image density, and performance paths.
@res Auto-Substitution (Roku)
On Roku, packaged resource URIs with @res auto-resolve based on manifest:
uri_resolution_autosub=@res,-sd,-hd,-fhd
Use pkg:/path/to/image@res.png and include the matching -sd, -hd, and -fhd files in your package.
Remote URLs
Remote HTTP(S) URLs do not go through Roku auto-substitution. Use resolveImageUri(url) to replace @res with a concrete suffix and to normalize pkg:/ URIs on web:
export function resolveImageUri(uri: string): string {
const normalizedUri = normalizePkgUri(uri);
return normalizedUri?.replace('@res', '-fhd') ?? '';
}
AppConfig Resolution
AppConfig is configured after the device resolves resolutionInfo. Fragment data bindings can use $RES$ in paths such as ${data.imageSet.$RES$}; AppConfig replaces it with the active suffix before the fragment reads item data.