UNPKG

@nativescript/core

Version:

A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.

1,456 lines • 67.7 kB
import { CoreTypes } from '../core-types';
import { profile } from '../profiling';
import { isEmbedded } from '../ui/embedding';
import { SDK_VERSION } from '../utils/constants';
import { android as androidUtils, dataSerialize } from '../utils';
import { ApplicationCommon } from './application-common';
import { Observable } from '../data/observable';
import { Trace } from '../trace';
import { AndroidNativeWindow } from '../native-window/native-window.android';
import { NativeWindow } from '../native-window/native-window-common';
import { NativeWindowEvents } from '../native-window/native-window-interfaces';
import { CommonA11YServiceEnabledObservable, SharedA11YObservable, notifyAccessibilityFocusState, a11yServiceClasses, a11yServiceDisabledClass, a11yServiceEnabledClass, fontScaleCategoryClasses, fontScaleExtraLargeCategoryClass, fontScaleExtraSmallCategoryClass, fontScaleMediumCategoryClass, getCurrentA11YServiceClass, getCurrentFontScaleCategory, getCurrentFontScaleClass, getFontScaleCssClasses, setCurrentA11YServiceClass, setCurrentFontScaleCategory, setCurrentFontScaleClass, setFontScaleCssClasses, setFontScale, getFontScale, setInitFontScale, getFontScaleCategory, setInitAccessibilityCssHelper, FontScaleCategory, getClosestValidFontScale, VALID_FONT_SCALES, AccessibilityRole, AccessibilityState, AndroidAccessibilityEvent, isA11yEnabled, setA11yEnabled, } from '../accessibility/accessibility-common';
import { androidGetForegroundActivity, androidGetStartActivity, androidSetForegroundActivity, androidSetStartActivity, applyContentDescription } from './helpers';
import { getImageFetcher, getNativeApp, getRootView, initImageCache, setA11yUpdatePropertiesCallback, setApplicationPropertiesCallback, setAppMainEntry, setNativeApp, setRootView, setToggleApplicationEventListenersCallback } from './helpers-common';
import { getNativeScriptGlobals } from '../globals/global-utils';
import { enableEdgeToEdge } from '../utils/native-helper-for-android';
import lazy from '../utils/lazy';
const WINDOW_ID_EXTRA = 'com.tns.activity.windowId';
let multiWindowWarned = false;
function warnMultiWindowIsExperimental() {
    if (multiWindowWarned) {
        return;
    }
    multiWindowWarned = true;
    const message = 'Application.android.openWindow() is experimental. The start activity must not use launchMode="singleTask" (the app template default) or "singleInstance" in AndroidManifest.xml, or Android hands the launch intent to the existing activity instead of opening a second one; use "singleInstancePerTask" (API 31+) or "standard".';
    Trace.write(message, Trace.categories.Debug, Trace.messageType.warn);
    console.warn(message);
}
let NativeScriptLifecycleCallbacks_;
function initNativeScriptLifecycleCallbacks() {
    if (NativeScriptLifecycleCallbacks_) {
        return NativeScriptLifecycleCallbacks_;
    }
    var NativeScriptLifecycleCallbacksImpl = (function (_super) {
        __extends(NativeScriptLifecycleCallbacksImpl, _super);
        function NativeScriptLifecycleCallbacksImpl() {
            var _this = _super !== null && _super.apply(this, arguments) || this;
            _this.activitiesCount = 0;
            return _this;
        }
        NativeScriptLifecycleCallbacksImpl.prototype.onActivityCreated = function (activity, savedInstanceState) {
            this.setThemeOnLaunch(activity);
            enableEdgeToEdge(activity);
            if (!Application.android.startActivity) {
                Application.android.setStartActivity(activity);
            }
            if (!this.nativescriptActivity && "isNativeScriptActivity" in activity) {
                this.nativescriptActivity = activity;
            }
            var savedWindowId = savedInstanceState === null || savedInstanceState === void 0 ? void 0 : savedInstanceState.getString(WINDOW_ID_EXTRA);
            var knownWindow = savedWindowId ? Application.android.getWindowById(savedWindowId) : undefined;
            var nativeWindow;
            if ((knownWindow === null || knownWindow === void 0 ? void 0 : knownWindow.state) === "detached") {
                knownWindow._reattach(activity);
                nativeWindow = knownWindow;
            }
            else {
                var isPrimary = Application.android._getWindows().length === 0;
                nativeWindow = new AndroidNativeWindow(activity, savedWindowId || AndroidNativeWindow.newWindowId(), isPrimary, isEmbedded() ? "embedded" : "application");
                Application.android._registerWindow(nativeWindow);
            }
            nativeWindow._registerConfigurationCallbacks();
            nativeWindow._notifyEvent(NativeWindowEvents.attached);
            this.notifyActivityCreated(activity, savedInstanceState, nativeWindow);
            if (Application.hasListeners(Application.displayedEvent)) {
                this.subscribeForGlobalLayout(activity);
            }
        };
        NativeScriptLifecycleCallbacksImpl.prototype.onActivityDestroyed = function (activity) {
            if (activity === Application.android.foregroundActivity) {
                Application.android.setForegroundActivity(undefined);
            }
            if (activity === this.nativescriptActivity) {
                this.nativescriptActivity = undefined;
            }
            if (activity === Application.android.startActivity) {
                Application.android.setStartActivity(undefined);
                if (this.nativescriptActivity) {
                    Application.android.setStartActivity(this.nativescriptActivity);
                }
            }
            var nativeWindow = Application.android._getWindowForActivity(activity);
            if (nativeWindow) {
                Application.android._setWindowActive(nativeWindow, false, activity);
                nativeWindow._surfaceGone = true;
                var isClosing = activity.isFinishing();
                if (isClosing) {
                    nativeWindow._notifyEvent(NativeWindowEvents.close);
                }
                nativeWindow.notify({
                    eventName: NativeWindowEvents.activityDestroyed,
                    object: nativeWindow,
                    window: nativeWindow,
                    activity: activity,
                });
                if (isClosing) {
                    Application.android._unregisterWindow(nativeWindow);
                }
                else {
                    nativeWindow._detach();
                }
            }
            Application.android.notify({
                eventName: Application.android.activityDestroyedEvent,
                object: Application.android,
                window: nativeWindow,
                activity: activity,
            });
            if (activity.isFinishing() && Application.android._getWindows().length === 0) {
                Application.android.notify({
                    eventName: Application.exitEvent,
                    object: Application.android,
                    android: activity,
                });
            }
            gc();
        };
        NativeScriptLifecycleCallbacksImpl.prototype.onActivityPaused = function (activity) {
            var nativeWindow = Application.android._getWindowForActivity(activity);
            if ("isNativeScriptActivity" in activity) {
                Application.android._setWindowActive(nativeWindow, false, activity);
            }
            if (nativeWindow) {
                nativeWindow._notifyEvent(NativeWindowEvents.deactivate);
                nativeWindow.notify({
                    eventName: NativeWindowEvents.activityPaused,
                    object: nativeWindow,
                    window: nativeWindow,
                    activity: activity,
                });
            }
            Application.android.notify({
                eventName: Application.android.activityPausedEvent,
                object: Application.android,
                window: nativeWindow,
                activity: activity,
            });
        };
        NativeScriptLifecycleCallbacksImpl.prototype.onActivityResumed = function (activity) {
            Application.android.setForegroundActivity(activity);
            var nativeWindow = Application.android._getWindowForActivity(activity);
            if (nativeWindow) {
                nativeWindow._notifyEvent(NativeWindowEvents.activate);
                nativeWindow.notify({
                    eventName: NativeWindowEvents.activityResumed,
                    object: nativeWindow,
                    window: nativeWindow,
                    activity: activity,
                });
            }
            Application.android.notify({
                eventName: Application.android.activityResumedEvent,
                object: Application.android,
                window: nativeWindow,
                activity: activity,
            });
        };
        NativeScriptLifecycleCallbacksImpl.prototype.onActivitySaveInstanceState = function (activity, bundle) {
            var nativeWindow = Application.android._getWindowForActivity(activity);
            if (nativeWindow) {
                bundle.putString(WINDOW_ID_EXTRA, nativeWindow.id);
                nativeWindow.notify({
                    eventName: NativeWindowEvents.saveActivityState,
                    object: nativeWindow,
                    window: nativeWindow,
                    activity: activity,
                    bundle: bundle,
                });
            }
            Application.android.notify({
                eventName: Application.android.saveActivityStateEvent,
                object: Application.android,
                window: nativeWindow,
                activity: activity,
                bundle: bundle,
            });
        };
        NativeScriptLifecycleCallbacksImpl.prototype.onActivityStarted = function (activity) {
            this.activitiesCount++;
            if (this.activitiesCount === 1) {
                Application.android.setInBackground(false, {
                    android: activity,
                    activity: activity,
                });
            }
            var nativeWindow = Application.android._getWindowForActivity(activity);
            if (nativeWindow) {
                nativeWindow._notifyEvent(NativeWindowEvents.foreground);
                nativeWindow.notify({
                    eventName: NativeWindowEvents.activityStarted,
                    object: nativeWindow,
                    window: nativeWindow,
                    activity: activity,
                });
            }
            Application.android.notify({
                eventName: Application.android.activityStartedEvent,
                object: Application.android,
                window: nativeWindow,
                activity: activity,
            });
        };
        NativeScriptLifecycleCallbacksImpl.prototype.onActivityStopped = function (activity) {
            this.activitiesCount--;
            if (this.activitiesCount === 0) {
                Application.android.setInBackground(true, {
                    android: activity,
                    activity: activity,
                });
            }
            var nativeWindow = Application.android._getWindowForActivity(activity);
            if (nativeWindow) {
                nativeWindow._notifyEvent(NativeWindowEvents.background);
                nativeWindow.notify({
                    eventName: NativeWindowEvents.activityStopped,
                    object: nativeWindow,
                    window: nativeWindow,
                    activity: activity,
                });
            }
            Application.android.notify({
                eventName: Application.android.activityStoppedEvent,
                object: Application.android,
                window: nativeWindow,
                activity: activity,
            });
        };
        NativeScriptLifecycleCallbacksImpl.prototype.setThemeOnLaunch = function (activity) {
            var activityInfo = activity.getPackageManager().getActivityInfo(activity.getComponentName(), android.content.pm.PackageManager.GET_META_DATA);
            if (activityInfo.metaData) {
                var setThemeOnLaunch = activityInfo.metaData.getInt("SET_THEME_ON_LAUNCH", -1);
                if (setThemeOnLaunch !== -1) {
                    activity.setTheme(setThemeOnLaunch);
                }
            }
        };
        NativeScriptLifecycleCallbacksImpl.prototype.notifyActivityCreated = function (activity, bundle, nativeWindow) {
            if (nativeWindow) {
                nativeWindow.notify({
                    eventName: NativeWindowEvents.activityCreated,
                    object: nativeWindow,
                    window: nativeWindow,
                    activity: activity,
                    bundle: bundle,
                });
            }
            Application.android.notify({
                eventName: Application.android.activityCreatedEvent,
                object: Application.android,
                window: nativeWindow,
                activity: activity,
                bundle: bundle,
            });
        };
        NativeScriptLifecycleCallbacksImpl.prototype.subscribeForGlobalLayout = function (activity) {
            var rootView = activity.getWindow().getDecorView().getRootView();
            global.onGlobalLayoutListener = new android.view.ViewTreeObserver.OnGlobalLayoutListener({
                onGlobalLayout: function () {
                    Application.android.notify({
                        eventName: Application.displayedEvent,
                        object: Application,
                        android: Application.android,
                        activity: activity,
                    });
                    var viewTreeObserver = rootView.getViewTreeObserver();
                    viewTreeObserver.removeOnGlobalLayoutListener(global.onGlobalLayoutListener);
                },
            });
            rootView.getViewTreeObserver().addOnGlobalLayoutListener(global.onGlobalLayoutListener);
        };
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "onActivityCreated", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "onActivityDestroyed", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "onActivityPaused", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "onActivityResumed", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "onActivitySaveInstanceState", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "onActivityStarted", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "onActivityStopped", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "setThemeOnLaunch", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "notifyActivityCreated", null);
        __decorate([
            profile
        ], NativeScriptLifecycleCallbacksImpl.prototype, "subscribeForGlobalLayout", null);
        NativeScriptLifecycleCallbacksImpl = __decorate([
            JavaProxy("org.nativescript.NativeScriptLifecycleCallbacks")
        ], NativeScriptLifecycleCallbacksImpl);
        return NativeScriptLifecycleCallbacksImpl;
    }(android.app.Application.ActivityLifecycleCallbacks));
    NativeScriptLifecycleCallbacks_ = NativeScriptLifecycleCallbacksImpl;
    return NativeScriptLifecycleCallbacks_;
}
let NativeScriptComponentCallbacks_;
function initNativeScriptComponentCallbacks() {
    if (NativeScriptComponentCallbacks_) {
        return NativeScriptComponentCallbacks_;
    }
    var NativeScriptComponentCallbacksImpl = (function (_super) {
        __extends(NativeScriptComponentCallbacksImpl, _super);
        function NativeScriptComponentCallbacksImpl() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        NativeScriptComponentCallbacksImpl.prototype.onLowMemory = function () {
            gc();
            java.lang.System.gc();
            Application.notify({
                eventName: Application.lowMemoryEvent,
                object: Application,
                android: this,
            });
        };
        NativeScriptComponentCallbacksImpl.prototype.onTrimMemory = function (level) {
        };
        NativeScriptComponentCallbacksImpl.prototype.onConfigurationChanged = function (newConfiguration) {
            Application.android.onConfigurationChanged(newConfiguration);
        };
        __decorate([
            profile
        ], NativeScriptComponentCallbacksImpl.prototype, "onLowMemory", null);
        __decorate([
            profile
        ], NativeScriptComponentCallbacksImpl.prototype, "onTrimMemory", null);
        __decorate([
            profile
        ], NativeScriptComponentCallbacksImpl.prototype, "onConfigurationChanged", null);
        NativeScriptComponentCallbacksImpl = __decorate([
            JavaProxy("org.nativescript.NativeScriptComponentCallbacks")
        ], NativeScriptComponentCallbacksImpl);
        return NativeScriptComponentCallbacksImpl;
    }(android.content.ComponentCallbacks2));
    NativeScriptComponentCallbacks_ = NativeScriptComponentCallbacksImpl;
    return NativeScriptComponentCallbacks_;
}
const BroadcastReceiver = lazy(() => {
    var BroadcastReceiverImpl = (function (_super) {
        __extends(BroadcastReceiverImpl, _super);
        function BroadcastReceiverImpl(onReceiveCallback) {
            var _this = _super.call(this) || this;
            _this._onReceiveCallback = onReceiveCallback;
            return global.__native(_this);
        }
        BroadcastReceiverImpl.prototype.onReceive = function (context, intent) {
            if (this._onReceiveCallback) {
                this._onReceiveCallback(context, intent);
            }
        };
        return BroadcastReceiverImpl;
    }(android.content.BroadcastReceiver));
    return BroadcastReceiverImpl;
});
export class AndroidApplication extends ApplicationCommon {
    constructor() {
        super(...arguments);
        this.activityCreatedEvent = AndroidApplication.activityCreatedEvent;
        this.activityDestroyedEvent = AndroidApplication.activityDestroyedEvent;
        this.activityStartedEvent = AndroidApplication.activityStartedEvent;
        this.activityPausedEvent = AndroidApplication.activityPausedEvent;
        this.activityResumedEvent = AndroidApplication.activityResumedEvent;
        this.activityStoppedEvent = AndroidApplication.activityStoppedEvent;
        this.saveActivityStateEvent = AndroidApplication.saveActivityStateEvent;
        this.activityResultEvent = AndroidApplication.activityResultEvent;
        this.activityBackPressedEvent = AndroidApplication.activityBackPressedEvent;
        this.activityNewIntentEvent = AndroidApplication.activityNewIntentEvent;
        this.activityRequestPermissionsEvent = AndroidApplication.activityRequestPermissionsEvent;
        // Windows currently active. Membership, not a count, so a repeated or missing lifecycle
        // callback cannot drift the aggregate. The registry owns window lifetime, so nothing here
        // outlives the window itself.
        this._activeWindows = new Set();
        this._registeredReceivers = {};
        this._registeredReceiversById = {};
        this._nextReceiverId = 1;
        this._pendingReceiverRegistrations = [];
    }
    init(nativeApp) {
        if (this.nativeApp === nativeApp) {
            return;
        }
        if (this.nativeApp) {
            throw new Error('Application.android already initialized.');
        }
        this._nativeApp = nativeApp;
        setNativeApp(nativeApp);
        this._context = nativeApp.getApplicationContext();
        this._packageName = nativeApp.getPackageName();
        // we store those callbacks and add a function for clearing them later so that the objects will be eligable for GC
        this.lifecycleCallbacks = new (initNativeScriptLifecycleCallbacks())();
        this.nativeApp.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
        this.componentCallbacks = new (initNativeScriptComponentCallbacks())();
        this.nativeApp.registerComponentCallbacks(this.componentCallbacks);
        this._registerPendingReceivers();
    }
    _registerPendingReceivers() {
        this._pendingReceiverRegistrations.forEach((info) => this._registerReceiver(this.context, info.intent, info.callback, info.flags, info.id));
        this._pendingReceiverRegistrations.length = 0;
    }
    onConfigurationChanged(configuration) {
        // The application context reports the app-wide configuration, which a window on a
        // second display or in split-screen does not necessarily share, so the primary
        // window is asked first. Each window tracks its own through its activity.
        const primaryWindow = this.primaryWindow;
        this.setOrientation(primaryWindow?.orientation() ?? this.getOrientationValue(configuration));
        this.setSystemAppearance(primaryWindow?.systemAppearance() ?? this.getSystemAppearanceValue(configuration));
        this.setLayoutDirection(primaryWindow?.layoutDirection() ?? this.getLayoutDirectionValue(configuration));
    }
    getNativeApplication() {
        let nativeApp = this.nativeApp;
        if (nativeApp) {
            return nativeApp;
        }
        nativeApp = getNativeApp();
        // we cannot work without having the app instance
        if (!nativeApp) {
            throw new Error("Failed to retrieve native Android Application object. If you have a custom android.app.Application type implemented make sure that you've called the 'Application.android.init' method.");
        }
        return nativeApp;
    }
    get nativeApp() {
        return this._nativeApp;
    }
    run(entry) {
        if (this.started) {
            throw new Error('Application is already started.');
        }
        this.started = true;
        setAppMainEntry(typeof entry === 'string' ? { moduleName: entry } : entry);
        if (!this.nativeApp) {
            const nativeApp = this.getNativeApplication();
            this.init(nativeApp);
        }
        // The activity lifecycle callbacks are registered but no activity has been created yet,
        // so this always precedes the first `windowOpen`.
        this.notifyReady();
    }
    get startActivity() {
        return androidGetStartActivity();
    }
    get foregroundActivity() {
        return androidGetForegroundActivity();
    }
    setStartActivity(value) {
        androidSetStartActivity(value);
    }
    setForegroundActivity(value) {
        androidSetForegroundActivity(value);
    }
    get paused() {
        return this.suspended;
    }
    get backgrounded() {
        return this.inBackground;
    }
    get context() {
        return this._context;
    }
    get packageName() {
        return this._packageName;
    }
    // Possible flags are:
    // RECEIVER_EXPORTED (2)
    // RECEIVER_NOT_EXPORTED (4)
    // RECEIVER_VISIBLE_TO_INSTANT_APPS (1)
    registerBroadcastReceiver(intentFilter, onReceiveCallback, flags = 2) {
        const receiverId = this._nextReceiverId++;
        if (this.context) {
            this._registerReceiver(this.context, intentFilter, onReceiveCallback, flags, receiverId);
        }
        else {
            this._pendingReceiverRegistrations.push({
                intent: intentFilter,
                callback: onReceiveCallback,
                id: receiverId,
                flags,
            });
        }
        let removed = false;
        return () => {
            if (removed) {
                return;
            }
            removed = true;
            if (this._registeredReceiversById[receiverId]) {
                const receiverInfo = this._registeredReceiversById[receiverId];
                this.context.unregisterReceiver(receiverInfo.receiver);
                this._registeredReceivers[receiverInfo.intent] = this._registeredReceivers[receiverInfo.intent]?.filter((ri) => ri.id !== receiverId);
                delete this._registeredReceiversById[receiverId];
            }
            else {
                this._pendingReceiverRegistrations = this._pendingReceiverRegistrations.filter((ri) => ri.id !== receiverId);
            }
        };
    }
    _registerReceiver(context, intentFilter, onReceiveCallback, flags, id) {
        var _a;
        const receiver = new (BroadcastReceiver())(onReceiveCallback);
        if (SDK_VERSION >= 26) {
            context.registerReceiver(receiver, new android.content.IntentFilter(intentFilter), flags);
        }
        else {
            context.registerReceiver(receiver, new android.content.IntentFilter(intentFilter));
        }
        const receiverInfo = { receiver, intent: intentFilter, callback: onReceiveCallback, id: typeof id === 'number' ? id : this._nextReceiverId++, flags };
        (_a = this._registeredReceivers)[intentFilter] ?? (_a[intentFilter] = []);
        this._registeredReceivers[intentFilter].push(receiverInfo);
        this._registeredReceiversById[receiverInfo.id] = receiverInfo;
        return receiver;
    }
    unregisterBroadcastReceiver(intentFilter) {
        const receivers = this._registeredReceivers[intentFilter];
        if (receivers) {
            receivers.forEach((receiver) => {
                this.context.unregisterReceiver(receiver.receiver);
            });
            this._registeredReceivers[intentFilter] = [];
        }
    }
    getRegisteredBroadcastReceiver(intentFilter) {
        return this._registeredReceivers[intentFilter]?.[0]?.receiver;
    }
    getRegisteredBroadcastReceivers(intentFilter) {
        const receiversInfo = this._registeredReceivers[intentFilter];
        if (receiversInfo) {
            return receiversInfo.map((info) => info.receiver);
        }
        return [];
    }
    // --- NativeWindow registry ---
    /**
     * @internal - Get a NativeWindow by its activity.
     */
    _getWindowForActivity(activity) {
        return this._windows.find((nw) => nw.android?.activity === activity);
    }
    /**
     * @internal - Feeds a window's active state into the application-level 'resume'/'suspend'
     * events, which describe the app as a whole: they are raised when the first window becomes
     * active and when the last active one resigns. Callers decide which activities may speak
     * for the app; every window reaching here participates.
     */
    _setWindowActive(nativeWindow, active, activity) {
        if (this._trackWindowActive(nativeWindow, active)) {
            this.setSuspended(!active, {
                // todo: deprecate event.android in favor of event.activity
                android: activity,
                activity,
            });
        }
    }
    /**
     * @returns whether the set flipped between empty and non-empty, which is the only point
     * at which app-level state changes.
     */
    _trackWindowActive(nativeWindow, active) {
        const wasPopulated = this._activeWindows.size > 0;
        // An activity with no registered window cannot join the aggregate, so it only speaks
        // for the app while no window holds the state.
        if (!nativeWindow) {
            return !wasPopulated;
        }
        if (active) {
            this._activeWindows.add(nativeWindow);
        }
        else {
            this._activeWindows.delete(nativeWindow);
        }
        return wasPopulated !== this._activeWindows.size > 0;
    }
    // --- Multi-window support ---
    /**
     * Opens a new window by launching the start activity into its own task.
     *
     * @param options Options for the new window. `options.data` is put on the launch
     * intent as extras and surfaces as the window's `data`.
     *
     * @experimental The start activity's `launchMode` in AndroidManifest.xml decides whether a
     * second instance can exist at all: `singleTask` (the app template default) and
     * `singleInstance` route the intent to the existing activity's `onNewIntent` instead of
     * creating one. `singleInstancePerTask` (API 31+) keeps single-task behavior for launcher
     * and deep-link starts while still allowing the `MULTIPLE_TASK`/`NEW_DOCUMENT` launch used
     * here; `standard` also works. When the app is already in split-screen, the new window
     * opens in the adjacent pane; otherwise it covers the current one and both show in recents.
     */
    openWindow(options) {
        warnMultiWindowIsExperimental();
        const context = this.context ?? this.getNativeApplication();
        const intent = new android.content.Intent();
        const startActivity = this.startActivity;
        if (startActivity) {
            intent.setClass(context, startActivity.getClass());
        }
        else {
            intent.setClassName(context, 'org.nativescript.NativeScriptActivity');
        }
        let flags = android.content.Intent.FLAG_ACTIVITY_NEW_TASK | android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK | android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
        const launcher = this.foregroundActivity ?? startActivity;
        if (SDK_VERSION >= 24 && launcher?.isInMultiWindowMode()) {
            flags |= android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
        }
        intent.setFlags(flags);
        const data = options?.data;
        if (data) {
            for (const key of Object.keys(data)) {
                intent.putExtra(key, dataSerialize(data[key], true));
            }
        }
        if (launcher) {
            launcher.startActivity(intent);
        }
        else {
            context.startActivity(intent);
        }
    }
    getRootView() {
        const activity = this.foregroundActivity || this.startActivity;
        if (!activity) {
            return undefined;
        }
        const callbacks = activity['_callbacks'];
        setRootView(callbacks ? callbacks.getRootView() : undefined);
        return getRootView();
    }
    resetRootView(entry) {
        super.resetRootView(entry);
        const activity = this.foregroundActivity || this.startActivity;
        if (!activity) {
            throw new Error('Cannot find android activity.');
        }
        // this.mainEntry = typeof entry === 'string' ? { moduleName: entry } : entry;
        const callbacks = activity['_callbacks'];
        if (!callbacks) {
            throw new Error('Cannot find android activity callbacks.');
        }
        callbacks.resetActivityContent(activity);
    }
    getSystemAppearance() {
        const resources = this.context.getResources();
        const configuration = resources.getConfiguration();
        return this.getSystemAppearanceValue(configuration);
    }
    // https://developer.android.com/guide/topics/ui/look-and-feel/darktheme#configuration_changes
    getSystemAppearanceValue(configuration) {
        const systemAppearance = configuration.uiMode & android.content.res.Configuration.UI_MODE_NIGHT_MASK;
        switch (systemAppearance) {
            case android.content.res.Configuration.UI_MODE_NIGHT_YES:
                return 'dark';
            case android.content.res.Configuration.UI_MODE_NIGHT_NO:
            case android.content.res.Configuration.UI_MODE_NIGHT_UNDEFINED:
                return 'light';
        }
    }
    getLayoutDirection() {
        const resources = this.context.getResources();
        const configuration = resources.getConfiguration();
        return this.getLayoutDirectionValue(configuration);
    }
    getLayoutDirectionValue(configuration) {
        const layoutDirection = configuration.getLayoutDirection();
        switch (layoutDirection) {
            case android.view.View.LAYOUT_DIRECTION_LTR:
                return CoreTypes.LayoutDirection.ltr;
            case android.view.View.LAYOUT_DIRECTION_RTL:
                return CoreTypes.LayoutDirection.rtl;
        }
    }
    getOrientation() {
        const resources = this.context.getResources();
        const configuration = resources.getConfiguration();
        return this.getOrientationValue(configuration);
    }
    getOrientationValue(configuration) {
        const orientation = configuration.orientation;
        switch (orientation) {
            case android.content.res.Configuration.ORIENTATION_LANDSCAPE:
                return 'landscape';
            case android.content.res.Configuration.ORIENTATION_PORTRAIT:
                return 'portrait';
            default:
                return 'unknown';
        }
    }
    get android() {
        // ensures Application.android is defined when running on Android
        return this;
    }
}
AndroidApplication.activityCreatedEvent = 'activityCreated';
AndroidApplication.activityDestroyedEvent = 'activityDestroyed';
AndroidApplication.activityStartedEvent = 'activityStarted';
AndroidApplication.activityPausedEvent = 'activityPaused';
AndroidApplication.activityResumedEvent = 'activityResumed';
AndroidApplication.activityStoppedEvent = 'activityStopped';
AndroidApplication.saveActivityStateEvent = 'saveActivityState';
AndroidApplication.activityResultEvent = 'activityResult';
AndroidApplication.activityBackPressedEvent = 'activityBackPressed';
AndroidApplication.activityNewIntentEvent = 'activityNewIntent';
AndroidApplication.activityRequestPermissionsEvent = 'activityRequestPermissions';
export * from './application-common';
export * from './application-interfaces';
export const Application = new AndroidApplication();
export const iOSApplication = undefined;
function fontScaleChanged(origFontScale) {
    const oldValue = getFontScale();
    setFontScale(getClosestValidFontScale(origFontScale));
    const currentFontScale = getFontScale();
    if (oldValue !== currentFontScale) {
        Application.notify({
            eventName: Application.fontScaleChangedEvent,
            object: Application,
            newValue: currentFontScale,
        });
    }
}
export function getCurrentFontScale() {
    setupConfigListener();
    return getFontScale();
}
function useAndroidFontScale() {
    fontScaleChanged(Number(Application.android.context.getResources().getConfiguration().fontScale));
}
let configChangedCallback;
function setupConfigListener() {
    if (configChangedCallback) {
        return;
    }
    Application.off(Application.launchEvent, setupConfigListener);
    const context = Application.android?.context;
    if (!context) {
        Application.on(Application.launchEvent, setupConfigListener);
        return;
    }
    useAndroidFontScale();
    configChangedCallback = new android.content.ComponentCallbacks2({
        onLowMemory() {
            // Dummy
        },
        onTrimMemory() {
            // Dummy
        },
        onConfigurationChanged(newConfig) {
            fontScaleChanged(Number(newConfig.fontScale));
        },
    });
    context.registerComponentCallbacks(configChangedCallback);
    Application.on(Application.resumeEvent, useAndroidFontScale);
}
setInitFontScale(setupConfigListener);
function applyRootCssClass(cssClasses, newCssClass) {
    const rootView = Application.getRootView();
    if (!rootView) {
        return;
    }
    Application.applyCssClass(rootView, cssClasses, newCssClass);
    const rootModalViews = rootView._getRootModalViews();
    rootModalViews.forEach((rootModalView) => Application.applyCssClass(rootModalView, cssClasses, newCssClass));
}
function applyFontScaleToRootViews() {
    const rootView = Application.getRootView();
    if (!rootView) {
        return;
    }
    const fontScale = getCurrentFontScale();
    rootView.style.fontScaleInternal = fontScale;
    const rootModalViews = rootView._getRootModalViews();
    rootModalViews.forEach((rootModalView) => (rootModalView.style.fontScaleInternal = fontScale));
}
export function getAndroidAccessibilityManager() {
    const context = getNativeApp().getApplicationContext();
    if (!context) {
        return null;
    }
    return context.getSystemService(android.content.Context.ACCESSIBILITY_SERVICE);
}
const accessibilityStateEnabledPropName = 'accessibilityStateEnabled';
const touchExplorationStateEnabledPropName = 'touchExplorationStateEnabled';
class AndroidSharedA11YObservable extends SharedA11YObservable {
    // @ts-ignore todo: fix
    get accessibilityServiceEnabled() {
        return !!this[accessibilityStateEnabledPropName] && !!this[touchExplorationStateEnabledPropName];
    }
    set accessibilityServiceEnabled(v) {
        return;
    }
}
let accessibilityStateChangeListener;
let touchExplorationStateChangeListener;
let sharedA11YObservable;
function updateAccessibilityState() {
    if (!sharedA11YObservable) {
        return;
    }
    const accessibilityManager = getAndroidAccessibilityManager();
    if (!accessibilityManager) {
        sharedA11YObservable.set(accessibilityStateEnabledPropName, false);
        sharedA11YObservable.set(touchExplorationStateEnabledPropName, false);
        return;
    }
    sharedA11YObservable.set(accessibilityStateEnabledPropName, !!accessibilityManager.isEnabled());
    sharedA11YObservable.set(touchExplorationStateEnabledPropName, !!accessibilityManager.isTouchExplorationEnabled());
}
function ensureStateListener() {
    if (sharedA11YObservable) {
        return sharedA11YObservable;
    }
    const accessibilityManager = getAndroidAccessibilityManager();
    sharedA11YObservable = new AndroidSharedA11YObservable();
    if (!accessibilityManager) {
        sharedA11YObservable.set(accessibilityStateEnabledPropName, false);
        sharedA11YObservable.set(touchExplorationStateEnabledPropName, false);
        return sharedA11YObservable;
    }
    accessibilityStateChangeListener = new android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener({
        onAccessibilityStateChanged(enabled) {
            updateAccessibilityState();
            if (Trace.isEnabled()) {
                Trace.write(`AccessibilityStateChangeListener state changed to: ${!!enabled}`, Trace.categories.Accessibility);
            }
        },
    });
    accessibilityManager.addAccessibilityStateChangeListener(accessibilityStateChangeListener);
    if (SDK_VERSION >= 19) {
        touchExplorationStateChangeListener = new android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener({
            onTouchExplorationStateChanged(enabled) {
                updateAccessibilityState();
                if (Trace.isEnabled()) {
                    Trace.write(`TouchExplorationStateChangeListener state changed to: ${!!enabled}`, Trace.categories.Accessibility);
                }
            },
        });
        accessibilityManager.addTouchExplorationStateChangeListener(touchExplorationStateChangeListener);
    }
    updateAccessibilityState();
    Application.on(Application.resumeEvent, updateAccessibilityState);
    Application.on(Application.exitEvent, (args) => {
        const activity = args.android;
        if (activity && !activity.isFinishing()) {
            return;
        }
        const accessibilityManager = getAndroidAccessibilityManager();
        if (accessibilityManager) {
            if (accessibilityStateChangeListener) {
                accessibilityManager.removeAccessibilityStateChangeListener(accessibilityStateChangeListener);
            }
            if (touchExplorationStateChangeListener) {
                accessibilityManager.removeTouchExplorationStateChangeListener(touchExplorationStateChangeListener);
            }
        }
        accessibilityStateChangeListener = null;
        touchExplorationStateChangeListener = null;
        if (sharedA11YObservable) {
            sharedA11YObservable.removeEventListener(Observable.propertyChangeEvent);
            sharedA11YObservable = null;
        }
        Application.off(Application.resumeEvent, updateAccessibilityState);
    });
    return sharedA11YObservable;
}
export class AccessibilityServiceEnabledObservable extends CommonA11YServiceEnabledObservable {
    constructor() {
        super(ensureStateListener());
    }
}
let accessibilityServiceObservable;
export function ensureA11yClasses() {
    if (accessibilityServiceObservable) {
        return;
    }
    setFontScaleCssClasses(new Map(VALID_FONT_SCALES.map((fs) => [fs, `a11y-fontscale-${Number(fs * 100).toFixed(0)}`])));
    accessibilityServiceObservable = new AccessibilityServiceEnabledObservable();
}
export function updateCurrentHelperClasses(applyRootCssClass) {
    const fontScale = getFontScale();
    const fontScaleCategory = getFontScaleCategory();
    const fontScaleCssClasses = getFontScaleCssClasses();
    const oldFontScaleClass = getCurrentFontScaleClass();
    if (fontScaleCssClasses.has(fontScale)) {
        setCurrentFontScaleClass(fontScaleCssClasses.get(fontScale));
    }
    else {
        setCurrentFontScaleClass(fontScaleCssClasses.get(1));
    }
    if (oldFontScaleClass !== getCurrentFontScaleClass()) {
        applyRootCssClass([...fontScaleCssClasses.values()], getCurrentFontScaleClass());
    }
    const oldActiveFontScaleCategory = getCurrentFontScaleCategory();
    switch (fontScaleCategory) {
        case FontScaleCategory.ExtraSmall: {
            setCurrentFontScaleCategory(fontScaleExtraSmallCategoryClass);
            break;
        }
        case FontScaleCategory.Medium: {
            setCurrentFontScaleCategory(fontScaleMediumCategoryClass);
            break;
        }
        case FontScaleCategory.ExtraLarge: {
            setCurrentFontScaleCategory(fontScaleExtraLargeCategoryClass);
            break;
        }
        default: {
            setCurrentFontScaleCategory(fontScaleMediumCategoryClass);
            break;
        }
    }
    if (oldActiveFontScaleCategory !== getCurrentFontScaleCategory()) {
        applyRootCssClass(fontScaleCategoryClasses, getCurrentFontScaleCategory());
    }
    const oldA11YStatusClass = getCurrentA11YServiceClass();
    if (accessibilityServiceObservable.accessibilityServiceEnabled) {
        setCurrentA11YServiceClass(a11yServiceEnabledClass);
    }
    else {
        setCurrentA11YServiceClass(a11yServiceDisabledClass);
    }
    if (oldA11YStatusClass !== getCurrentA11YServiceClass()) {
        applyRootCssClass(a11yServiceClasses, getCurrentA11YServiceClass());
    }
}
export function initAccessibilityCssHelper() {
    ensureA11yClasses();
    updateCurrentHelperClasses(applyRootCssClass);
    applyFontScaleToRootViews();
    Application.on(Application.fontScaleChangedEvent, () => {
        updateCurrentHelperClasses(applyRootCssClass);
        applyFontScaleToRootViews();
    });
    accessibilityServiceObservable.on(AccessibilityServiceEnabledObservable.propertyChangeEvent, () => updateCurrentHelperClasses(applyRootCssClass));
}
setInitAccessibilityCssHelper(initAccessibilityCssHelper);
let clickableRolesMap = new Set();
let lastFocusedView;
function accessibilityEventHelper(view, eventType) {
    const eventName = accessibilityEventTypeMap.get(eventType);
    if (!isAccessibilityServiceEnabled()) {
        if (Trace.isEnabled()) {
            Trace.write(`accessibilityEventHelper: Service not active`, Trace.categories.Accessibility);
        }
        return;
    }
    if (!eventName) {
        Trace.write(`accessibilityEventHelper: unknown eventType: ${eventType}`, Trace.categories.Accessibility, Trace.messageType.error);
        return;
    }
    if (!view) {
        if (Trace.isEnabled()) {
            Trace.write(`accessibilityEventHelper: no owner: ${eventName}`, Trace.categories.Accessibility);
        }
        return;
    }
    const androidView = view.nativeViewProtected;
    if (!androidView) {
        if (Trace.isEnabled()) {
            Trace.write(`accessibilityEventHelper: no nativeView`, Trace.categories.Accessibility);
        }
        return;
    }
    switch (eventType) {
        case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED: {
            /**
             * Android API >= 26 handles accessibility tap-events by converting them to TYPE_VIEW_CLICKED
             * These aren't triggered for custom tap events in NativeScript.
             */
            if (SDK_VERSION >= 26) {
                // Find all tap gestures and trigger them.
                for (const tapGesture of view.getGestureObservers(1) ?? []) {
                    tapGesture.callback({
                        android: view.android,
                        eventName: 'tap',
                        ios: null,
                        object: view,
                        type: 1,
                        view: view,
                    });
                }
            }
            return;
        }
        case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
            const lastView = lastFocusedView?.get();
            if (lastView && view !== lastView) {
                const lastAndroidView = lastView.nativeViewProtected;
                if (lastAndroidView) {
                    lastAndroidView.clearFocus();
                    lastFocusedView = null;
                    notifyAccessibilityFocusState(lastView, false, true);
                }
            }
            lastFocusedView = new WeakRef(view);
            notifyAccessibilityFocusState(view, true, false);
            return;
        }
        case android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
            const lastView = lastFocusedView?.get();
            if (lastView && view === lastView) {
                lastFocusedView = null;
                androidView.clearFocus();
            }
            notifyAccessibilityFocusState(view, false, true);
            return;
        }
    }
}
let TNSAccessibilityDelegate;
const androidViewToTNSView = new WeakMap();
let accessibilityEventMap;
let accessibilityEventTypeMap;
function ensureNativeClasses() {
    if (TNSAccessibilityDelegate) {
        return;
    }
    // WORKAROUND: Typing refers to android.view.View.androidviewViewAccessibilityDelegate but it is called android.view.View.AccessibilityDelegate at runtime
    const AccessibilityDelegate = android.view.View['AccessibilityDelegate'];
    const RoleTypeMap = new Map([
        [AccessibilityRole.Button, android.widget.Button.class.getName()],
        [AccessibilityRole.Search, android.widget.EditText.class.getName()],
        [AccessibilityRole.Image, android.widget.ImageView.class.getName()],
        [AccessibilityRole.ImageButton, android.widget.ImageButton.class.getName()],
        [AccessibilityRole.KeyboardKey, android.inputmethodservice.Keyboard.Key.class.getName()],
        [AccessibilityRole.StaticText, android.widget.TextView.class.getName()],
        [AccessibilityRole.Adjustable, android.widget.SeekBar.class.getName()],
        [AccessibilityRole.Checkbox, android.widget.CheckBox.class.getName()],
        [AccessibilityRole.RadioButton, android.widget.RadioButton.class.getName()],
        [AccessibilityRole.SpinButton, android.widget.Spinner.class.getName()],
        [AccessibilityRole.Switch, android.widget.Switch.class.getName()],
        [AccessibilityRole.ProgressBar, android.widget.ProgressBar.class.getName()],
    ]);
    clickableRolesMap = new Set([AccessibilityRole.Button, AccessibilityRole.ImageButton]);
    const ignoreRoleTypesForTrace = new Set([AccessibilityRole.Header, AccessibilityRole.Link, AccessibilityRole.None, AccessibilityRole.Summary]);
    var TNSAccessibilityDelegateImpl = (function (_super) {
        __extends(TNSAccessibilityDelegateImpl, _super);
        function TNSAccessibilityDelegateImpl() {
            var _this = _super.call(this) || this;
            return global.__native(_this);
        }
        TNSAccessibilityDelegateImpl.prototype.getTnsView = function (androidView) {
            var _a;
            var view = (_a = androidViewToTNSView.get(androidView)) === null || _a === void 0 ? void 0 : _a.get();
            if (!view) {
                androidViewToTNSView.delete(androidView);
                return null;
            }
            return view;
        };
        TNSAccessibilityDelegateImpl.prototype.onInitializeAccessibilityNodeInfo = function (host, info) {
            _super.prototype.onInitializeAccessibilityNodeInfo.call(this, host, info);
            var view = this.getTnsView(host);
            if (!view) {
                if (Trace.isEnabled()) {
                    Trace.write("onInitializeAccessibilityNodeInfo ".concat(host, " ").concat(info, " no tns-view"), Trace.categories.Accessibility);
                }
                return;
            }
            var id = host.getTag(androidUtils.resources.getId(":id/nativescript_accessibility_id"));
            if (id != null) {
                info.setViewIdResourceName(id);
            }
            var accessibilityRole = view.accessibilityRole;
            if (accessibilityRole) {
                var androidClassName = RoleTypeMap.get(accessibilityRole);
                if (androidClassName) {
                    var oldClassName = info.getClassName() || (SDK_VERSION >= 28 && host.getAccessibilityClassName()) || null;
                    info.setClassName(androidClassName);
                    if (Trace.isEnabled()) {
                        Trace.write("".concat(view, ".accessibilityRole = \"").concat(accessibilityRole, "\" is mapped to \"").concat(androidClassName, "\" (was ").concat(oldClassName, "). ").concat(info.getClassName()), Trace.categories.Accessibility);
                    }
                }
                else if (!ignoreRoleTypesForTrace.has(accessibilityRole)) {
                    if (Trace.isEnabled()) {
                        Trace.write("".concat(view, ".accessibilityRole = \"").concat(accessibilityRole, "\" is unknown"), Trace.categories.Accessibility);
                    }
                }
                if (clickableRolesMap.has(accessibilityRole)) {
                    if (Trace.isEnabled()) {
                        Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set clickable role=").concat(accessibilityRole), Trace.categories.Accessibility);
                    }
                    info.setClickable(true);
                }
                if (SDK_VERSION >= 28) {
                    if (accessibilityRole === AccessibilityRole.Header) {
                        if (Trace.isEnabled()) {
                            Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set heading role=").concat(accessibilityRole), Trace.categories.Accessibility);
                        }
                        info.setHeading(true);
                    }
                    else if (host.isAccessibilityHeading()) {
                        if (Trace.isEnabled()) {
                            Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set heading from host"), Trace.categories.Accessibility);
                        }
                        info.setHeading(true);
                    }
                    else {
                        if (Trace.isEnabled()) {
                            Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set not heading"), Trace.categories.Accessibility);
                        }
                        info.setHeading(false);
                    }
                }
                switch (accessibilityRole) {
                    case AccessibilityRole.Switch:
                    case AccessibilityRole.RadioButton:
                    case AccessibilityRole.Checkbox: {
                        if (Trace.isEnabled()) {
                            Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set checkable and check=").concat(view.accessibilityState === AccessibilityState.Checked), Trace.categories.Accessibility);
                        }
                        info.setCheckable(true);
                        info.setChecked(view.accessibilityState === AccessibilityState.Checked);
                        break;
                    }
                    default: {
                        if (Trace.isEnabled()) {
                            Trace.write("onInitializeAccessibilityNodeInfo ".concat(view, " - set enabled=").concat(view.accessibilityState !== AccessibilityState.Disabled, " and selected=").concat(view.accessibilityState === AccessibilityState.Selected), Trace.categories.Accessibility);
                        }
                        info.setEnabled(view.accessibilityState !== AccessibilityState.Disabled);
                        info.setSelected(view.accessibilityState === AccessibilityState.Selected);
                        break;
                    }
                }
            }
            if (view.accessible) {
                info.setFocusable(true);
            }
            // mean either a second window for this activity or a window with the wrong role.
        };
        TNSAccessibilityDelegateImpl.prototype.sendAccessibilityEvent = function (host, eventType) {
            _super.prototype.sendAccessibilityEvent.call(this, host, eventType);
            var view = this.getTnsView(host);
            if (!view) {
                console.log("skip - ".concat(host, " - ").concat(accessibilityEventTypeMap.get(eventType)));
                return;
            }
            try {
                accessibilityEventHelper(view, eventType);
            }
            catch (err) {
                console.error(err);
            }
        };
        return TNSAccessibilityDelegateImpl;
    }(AccessibilityDelegate));
    TNSAccessibilityDelegate = new TNSAccessibilityDelegateImpl();
    accessibilityEventMap = new Map([
        /**
         * Invalid selection/focus position.
         */
        [AndroidAccessibilityEvent.INVALID_POSITION, android.view.accessibility.AccessibilityEvent.INVALID_POSITION],
        /**
         * Maximum length of the text fields.
         */
        [AndroidAccessibilityEvent.MAX_TEXT_LENGTH, android.view.accessibility.AccessibilityEvent.MAX_TEXT_LENGTH],
        /**
         * Represents the event of clicking on a android.view.View like android.widget.Button, android.widget.CompoundButton, etc.
         */
        [AndroidAccessibilityEvent.VIEW_CLICKED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_CLICKED],
        /**
         * Represents the event of long clicking on a android.view.View like android.widget.Button, android.widget.CompoundButton, etc.
         */
        [AndroidAccessibilityEvent.VIEW_LONG_CLICKED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_LONG_CLICKED],
        /**
         * Represents the event of selecting an item usually in the context of an android.widget.AdapterView.
         */
        [AndroidAccessibilityEvent.VIEW_SELECTED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SELECTED],
        /**
         * Represents the event of setting input focus of a android.view.View.
         */
        [AndroidAccessibilityEvent.VIEW_FOCUSED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED],
        /**
         * Represents the event of changing the text of an android.widget.EditText.
         */
        [AndroidAccessibilityEvent.VIEW_TEXT_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED],
        /**
         * Represents the event of opening a android.widget.PopupWindow, android.view.Menu, android.app.Dialog, etc.
         */
        [AndroidAccessibilityEvent.WINDOW_STATE_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED],
        /**
         * Represents the event showing a android.app.Notification.
         */
        [AndroidAccessibilityEvent.NOTIFICATION_STATE_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED],
        /**
         * Represents the event of a hover enter over a android.view.View.
         */
        [AndroidAccessibilityEvent.VIEW_HOVER_ENTER, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_ENTER],
        /**
         * Represents the event of a hover exit over a android.view.View.
         */
        [AndroidAccessibilityEvent.VIEW_HOVER_EXIT, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_HOVER_EXIT],
        /**
         * Represents the event of starting a touch exploration gesture.
         */
        [AndroidAccessibilityEvent.TOUCH_EXPLORATION_GESTURE_START, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START],
        /**
         * Represents the event of ending a touch exploration gesture.
         */
        [AndroidAccessibilityEvent.TOUCH_EXPLORATION_GESTURE_END, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END],
        /**
         * Represents the event of changing the content of a window and more specifically the sub-tree rooted at the event's source.
         */
        [AndroidAccessibilityEvent.WINDOW_CONTENT_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED],
        /**
         * Represents the event of scrolling a view.
         */
        [AndroidAccessibilityEvent.VIEW_SCROLLED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_SCROLLED],
        /**
         * Represents the event of changing the selection in an android.widget.EditText.
         */
        [AndroidAccessibilityEvent.VIEW_TEXT_SELECTION_CHANGED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED],
        /**
         * Represents the event of an application making an announcement.
         */
        [AndroidAccessibilityEvent.ANNOUNCEMENT, android.view.accessibility.AccessibilityEvent.TYPE_ANNOUNCEMENT],
        /**
         * Represents the event of gaining accessibility focus.
         */
        [AndroidAccessibilityEvent.VIEW_ACCESSIBILITY_FOCUSED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED],
        /**
         * Represents the event of clearing accessibility focus.
         */
        [AndroidAccessibilityEvent.VIEW_ACCESSIBILITY_FOCUS_CLEARED, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED],
        /**
         * Represents the event of traversing the text of a view at a given movement granularity.
         */
        [AndroidAccessibilityEvent.VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY, android.view.accessibility.AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY],
        /**
         * Represents the event of beginning gesture detection.
         */
        [AndroidAccessibilityEvent.GESTURE_DETECTION_START, android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_START],
        /**
         * Represents the event of ending gesture detection.
         */
        [AndroidAccessibilityEvent.GESTURE_DETECTION_END, android.view.accessibility.AccessibilityEvent.TYPE_GESTURE_DETECTION_END],
        /**
         * Represents the event of the user starting to touch the screen.
         */
        [AndroidAccessibilityEvent.TOUCH_INTERACTION_START, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_START],
        /**
         * Represents the event of the user ending to touch the screen.
         */
        [AndroidAccessibilityEvent.TOUCH_INTERACTION_END, android.view.accessibility.AccessibilityEvent.TYPE_TOUCH_INTERACTION_END],
        /**
         * Mask for AccessibilityEvent all types.
         */
        [AndroidAccessibilityEvent.ALL_MASK, android.view.accessibility.AccessibilityEvent.TYPES_ALL_MASK],
    ]);
    accessibilityEventTypeMap = new Map([...accessibilityEventMap].map(([k, v]) => [v, k]));
}
function updateAccessibilityServiceState() {
    const accessibilityManager = getAndroidAccessibilityManager();
    if (!accessibilityManager) {
        return;
    }
    setA11yEnabled(!!accessibilityManager.isEnabled() && !!accessibilityManager.isTouchExplorationEnabled());
}
export function isAccessibilityServiceEnabled() {
    const accessibilityServiceEnabled = isA11yEnabled();
    if (typeof accessibilityServiceEnabled === 'boolean') {
        return accessibilityServiceEnabled;
    }
    const accessibilityManager = getAndroidAccessibilityManager();
    accessibilityStateChangeListener = new android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener({
        onAccessibilityStateChanged(enabled) {
            updateAccessibilityServiceState();
            if (Trace.isEnabled()) {
                Trace.write(`AccessibilityStateChangeListener state changed to: ${!!enabled}`, Trace.categories.Accessibility);
            }
        },
    });
    accessibilityManager.addAccessibilityStateChangeListener(accessibilityStateChangeListener);
    if (SDK_VERSION >= 19) {
        touchExplorationStateChangeListener = new android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener({
            onTouchExplorationStateChanged(enabled) {
                updateAccessibilityServiceState();
                if (Trace.isEnabled()) {
                    Trace.write(`TouchExplorationStateChangeListener state changed to: ${!!enabled}`, Trace.categories.Accessibility);
                }
            },
        });
        accessibilityManager.addTouchExplorationStateChangeListener(touchExplorationStateChangeListener);
    }
    updateAccessibilityServiceState();
    Application.on(Application.exitEvent, (args) => {
        const activity = args.android;
        if (activity && !activity.isFinishing()) {
            return;
        }
        const accessibilityManager = getAndroidAccessibilityManager();
        if (accessibilityManager) {
            if (accessibilityStateChangeListener) {
                accessibilityManager.removeAccessibilityStateChangeListener(accessibilityStateChangeListener);
            }
            if (touchExplorationStateChangeListener) {
                accessibilityManager.removeTouchExplorationStateChangeListener(touchExplorationStateChangeListener);
            }
        }
        accessibilityStateChangeListener = null;
        touchExplorationStateChangeListener = null;
        Application.off(Application.resumeEvent, updateAccessibilityServiceState);
    });
    Application.on(Application.resumeEvent, updateAccessibilityServiceState);
    return accessibilityServiceEnabled;
}
let updateAccessibilityPropertiesMicroTask;
let pendingViews = new Set();
export function updateAccessibilityProperties(view) {
    if (!view.nativeViewProtected) {
        return;
    }
    pendingViews.add(view);
    if (updateAccessibilityPropertiesMicroTask)
        return;
    updateAccessibilityPropertiesMicroTask = true;
    Promise.resolve().then(() => {
        updateAccessibilityPropertiesMicroTask = false;
        let _pendingViews = Array.from(pendingViews);
        pendingViews = new Set();
        for (const view of _pendingViews) {
            if (!view.nativeViewProtected)
                continue;
            setAccessibilityDelegate(view);
            applyContentDescription(view);
        }
        _pendingViews = [];
    });
}
setA11yUpdatePropertiesCallback(updateAccessibilityProperties);
export function sendAccessibilityEvent(view, eventType, text) {
    if (!isAccessibilityServiceEnabled()) {
        return;
    }
    const cls = `sendAccessibilityEvent(${view}, ${eventType}, ${text})`;
    const androidView = view.nativeViewProtected;
    if (!androidView) {
        if (Trace.isEnabled()) {
            Trace.write(`${cls}: no nativeView`, Trace.categories.Accessibility);
        }
        return;
    }
    if (!eventType) {
        if (Trace.isEnabled()) {
            Trace.write(`${cls}: no eventName provided`, Trace.categories.Accessibility);
        }
        return;
    }
    if (!isAccessibilityServiceEnabled()) {
        if (Trace.isEnabled()) {
            Trace.write(`${cls} - TalkBack not enabled`, Trace.categories.Accessibility);
        }
        return;
    }
    const accessibilityManager = getAndroidAccessibilityManager();
    if (!accessibilityManager?.isEnabled()) {
        if (Trace.isEnabled()) {
            Trace.write(`${cls} - accessibility service not enabled`, Trace.categories.Accessibility);
        }
        return;
    }
    if (!accessibilityEventMap.has(eventType)) {
        if (Trace.isEnabled()) {
            Trace.write(`${cls} - unknown event`, Trace.categories.Accessibility);
        }
        return;
    }
    const eventInt = accessibilityEventMap.get(eventType);
    if (!text) {
        return androidView.sendAccessibilityEvent(eventInt);
    }
    const accessibilityEvent = android.view.accessibility.AccessibilityEvent.obtain(eventInt);
    accessibilityEvent.setSource(androidView);
    accessibilityEvent.getText().clear();
    if (!text) {
        applyContentDescription(view);
        text = androidView.getContentDescription() || view['title'];
        if (Trace.isEnabled()) {
            Trace.write(`${cls} - text not provided use androidView.getContentDescription() - ${text}`, Trace.categories.Accessibility);
        }
    }
    if (Trace.isEnabled()) {
        Trace.write(`${cls}: send event with text: '${JSON.stringify(text)}'`, Trace.categories.Accessibility);
    }
    if (text) {
        accessibilityEvent.getText().add(text);
    }
    accessibilityManager.sendAccessibilityEvent(accessibilityEvent);
}
function setAccessibilityDelegate(view) {
    if (!view.nativeViewProtected) {
        return;
    }
    ensureNativeClasses();
    const androidView = view.nativeViewProtected;
    if (!androidView || !androidView.setAccessibilityDelegate) {
        return;
    }
    androidViewToTNSView.set(androidView, new WeakRef(view));
    let hasOldDelegate = false;
    if (typeof androidView.getAccessibilityDelegate === 'function') {
        hasOldDelegate = androidView.getAccessibilityDelegate() === TNSAccessibilityDelegate;
    }
    if (hasOldDelegate) {
        return;
    }
    androidView.setAccessibilityDelegate(TNSAccessibilityDelegate);
}
const applicationEvents = [Application.orientationChangedEvent, Application.systemAppearanceChangedEvent];
function toggleApplicationEventListeners(toAdd, callback) {
    for (const eventName of applicationEvents) {
        if (toAdd) {
            Application.on(eventName, callback);
        }
        else {
            Application.off(eventName, callback);
        }
    }
}
setToggleApplicationEventListenersCallback(toggleApplicationEventListeners);
setApplicationPropertiesCallback(() => {
    return {
        orientation: Application.orientation(),
        systemAppearance: Application.systemAppearance(),
    };
});
function onLiveSync(args) {
    if (getImageFetcher()) {
        getImageFetcher().clearCache();
    }
}
getNativeScriptGlobals().events.on('livesync', onLiveSync);
getNativeScriptGlobals().addEventWiring(() => {
    Application.android.on('activityStarted', (args) => {
        if (!getImageFetcher()) {
            initImageCache(args.activity);
        }
        else {
            getImageFetcher().initCache();
        }
    });
});
getNativeScriptGlobals().addEventWiring(() => {
    Application.android.on('activityStopped', (args) => {
        if (getImageFetcher()) {
            getImageFetcher().closeCache();
        }
    });
});
//# sourceMappingURL=application.android.js.map