Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Gluon
* Copyright (c) 2016, 2026, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -174,4 +174,17 @@ static Optional<DisplayService> create() {
*/
ReadOnlyObjectProperty<Insets> systemBarsInsetsProperty();

/**
* Sets whether the device screen should remain always on, preventing the
* device from going to sleep or dimming the display.
*
* <p>The default value is {@code false}. When the application is closed
* or paused, the screen will revert to its default behavior.</p>
*
* @param alwaysOn if {@code true}, the screen will stay on; if {@code false},
* the default screen timeout behavior is restored
* @since 4.0.25
*/
void setScreenAlwaysOn(boolean alwaysOn);

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Gluon
* Copyright (c) 2016, 2026, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -28,6 +28,8 @@
package com.gluonhq.attach.display.impl;

import com.gluonhq.attach.display.DisplayService;
import com.gluonhq.attach.lifecycle.LifecycleEvent;
import com.gluonhq.attach.lifecycle.LifecycleService;
import com.gluonhq.attach.util.Util;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectProperty;
Expand All @@ -48,11 +50,25 @@ public class AndroidDisplayService implements DisplayService {

private static final boolean debug = Util.DEBUG;

private boolean screenAlwaysOn;

static {
System.loadLibrary("display");
}

public AndroidDisplayService() {
LifecycleService.create().ifPresent(l -> {
l.addListener(LifecycleEvent.PAUSE, () -> {
if (screenAlwaysOn) {
setScreenAlwaysOnNative(false);
}
});
l.addListener(LifecycleEvent.RESUME, () -> {
if (screenAlwaysOn) {
setScreenAlwaysOnNative(true);
}
});
});
}

@Override
Expand Down Expand Up @@ -127,10 +143,17 @@ public ReadOnlyObjectProperty<Insets> systemBarsInsetsProperty() {
return insetsProperty.getReadOnlyProperty();
}

@Override
public void setScreenAlwaysOn(boolean alwaysOn) {
this.screenAlwaysOn = alwaysOn;
setScreenAlwaysOnNative(alwaysOn);
}

// native
private native static boolean isPhoneFactor();
private native static double[] screenSize();
private native static boolean screenRound();
private native static void setScreenAlwaysOnNative(boolean alwaysOn);

// callback
private static void notifyInsets(double top, double right, double bottom, double left) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Gluon
* Copyright (c) 2016, 2026, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -109,6 +109,11 @@ public ReadOnlyObjectProperty<Insets> systemBarsInsetsProperty() {
return insetsProperty.getReadOnlyProperty();
}

@Override
public void setScreenAlwaysOn(boolean alwaysOn) {
// no-op
}

private static void log(String message, Throwable cause) {
LOG.log(Level.FINE, message);
if (LOG.isLoggable(Level.FINE)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Gluon
* Copyright (c) 2016, 2026, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -47,11 +47,23 @@ public class IOSDisplayService implements DisplayService {

private static final ReadOnlyObjectWrapper<Insets> insetsProperty = new ReadOnlyObjectWrapper<>();

private boolean screenAlwaysOn;

public IOSDisplayService() {
notch = new ReadOnlyObjectWrapper<>(Notch.UNKNOWN);
LifecycleService.create().ifPresent(l -> {
l.addListener(LifecycleEvent.PAUSE, IOSDisplayService::stopObserver);
l.addListener(LifecycleEvent.RESUME, IOSDisplayService::startObserver);
l.addListener(LifecycleEvent.PAUSE, () -> {
stopObserver();
if (screenAlwaysOn) {
setScreenAlwaysOnNative(false);
}
});
l.addListener(LifecycleEvent.RESUME, () -> {
startObserver();
if (screenAlwaysOn) {
setScreenAlwaysOnNative(true);
}
});
});
startObserver();
}
Expand Down Expand Up @@ -108,6 +120,12 @@ public ReadOnlyObjectProperty<Insets> systemBarsInsetsProperty() {
return insetsProperty.getReadOnlyProperty();
}

@Override
public void setScreenAlwaysOn(boolean alwaysOn) {
this.screenAlwaysOn = alwaysOn;
setScreenAlwaysOnNative(alwaysOn);
}

// native
private static native void initDisplay();

Expand All @@ -119,6 +137,7 @@ public ReadOnlyObjectProperty<Insets> systemBarsInsetsProperty() {

private static native void startObserver();
private static native void stopObserver();
private static native void setScreenAlwaysOnNative(boolean alwaysOn);

// callback
private static void notifyDisplay(String o) {
Expand Down
12 changes: 11 additions & 1 deletion modules/display/src/main/native/android/c/display.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Gluon
* Copyright (c) 2020, 2026, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -33,6 +33,7 @@ static jmethodID jDisplayServiceWidthMethod;
static jmethodID jDisplayServiceHeightMethod;
static jmethodID jDisplayServiceFactorMethod;
static jmethodID jDisplayServiceRoundMethod;
static jmethodID jDisplayServiceScreenAlwaysOnMethod;

// Graal handles
static jclass jGraalDisplayClass;
Expand All @@ -46,6 +47,7 @@ static void initializeDisplayDalvikHandles() {
jDisplayServiceHeightMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "screenHeight", "()D");
jDisplayServiceFactorMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "isPhoneFactor", "()Z");
jDisplayServiceRoundMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "isScreenRound", "()Z");
jDisplayServiceScreenAlwaysOnMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "setScreenAlwaysOn", "(Z)V");

jobject jActivity = substrateGetActivity();
jobject jtmpobj = (*dalvikEnv)->NewObject(dalvikEnv, jDisplayServiceClass, jDisplayServiceInitMethod, jActivity);
Expand Down Expand Up @@ -120,6 +122,14 @@ JNIEXPORT jboolean JNICALL Java_com_gluonhq_attach_display_impl_AndroidDisplaySe
return answer;
}

JNIEXPORT void JNICALL Java_com_gluonhq_attach_display_impl_AndroidDisplayService_setScreenAlwaysOnNative
(JNIEnv *env, jclass jClass, jboolean alwaysOn)
{
ATTACH_DALVIK();
(*dalvikEnv)->CallVoidMethod(dalvikEnv, jDalvikDisplayService, jDisplayServiceScreenAlwaysOnMethod, alwaysOn);
DETACH_DALVIK();
}

///////////////////////////
// From Dalvik to native //
///////////////////////////
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2025, Gluon
* Copyright (c) 2020, 2026, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -99,5 +99,25 @@ private void notifyInsets(WindowInsetsCompat insets, double density) {
systemBars.bottom / density, systemBars.left / density);
}

private void setScreenAlwaysOn(final boolean alwaysOn) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
Window window = activity.getWindow();
if (alwaysOn) {
if (Util.isDebug()) {
Log.v(TAG, "Setting screen always on");
}
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
} else {
if (Util.isDebug()) {
Log.v(TAG, "Clearing screen always on");
}
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
}
});
}

private native void notifyInsets(double top, double right, double bottom, double left);
}
13 changes: 12 additions & 1 deletion modules/display/src/main/native/ios/Display.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2025, Gluon
* Copyright (c) 2016, 2026, Gluon
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -146,6 +146,17 @@
return;
}

JNIEXPORT void JNICALL Java_com_gluonhq_attach_display_impl_IOSDisplayService_setScreenAlwaysOnNative
(JNIEnv *env, jclass jClass, jboolean alwaysOn)
{
dispatch_async(dispatch_get_main_queue(), ^{
if (debugAttach) {
AttachLog(@"Setting idleTimerDisabled to %s", alwaysOn ? "YES" : "NO");
}
[UIApplication sharedApplication].idleTimerDisabled = alwaysOn ? YES : NO;
});
}

void sendNotch() {
NSString *notch = [_display getNotch];
if (debugAttach) {
Expand Down
Loading