Skip to content
Open
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
30 changes: 30 additions & 0 deletions doc/source/apis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,36 @@ This can be used to prevent errors like:
Because the python function is called from the PythonActivity thread, you
need to be careful about your own calls.

Handling DarkMode
~~~~~~~~~~~~~~~~~

The ``android.darkmode`` module provides functionality to detect and respond to
system dark mode changes on Android devices.

You can set up a listener to monitor dark mode state changes using the
``set_dark_mode_listener`` function::

from android.darkmode import set_dark_mode_listener

def on_dark_mode_changed(is_dark_mode):
if is_dark_mode:
print('Dark mode is now enabled')
# Update your app's theme to dark mode
else:
print('Dark mode is now disabled')
# Update your app's theme to light mode

# Register the listener
set_dark_mode_listener(on_dark_mode_changed)

To remove the listener, simply pass ``None``::

set_dark_mode_listener(None)

The callback function receives a single boolean parameter ``is_dark_mode`` that
indicates whether dark mode is currently enabled (``True``) or disabled (``False``).



Advanced Android API use
------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.SystemClock;
Expand Down Expand Up @@ -238,4 +239,26 @@ public static void stop_service() {
Intent serviceIntent = new Intent(PythonActivity.mActivity, PythonService.class);
PythonActivity.mActivity.stopService(serviceIntent);
}

public interface DarkModeListener {
void onDarkModeChanged(boolean isDarkMode);
}

private DarkModeListener darkModeListener = null;

public void setDarkModeListener(DarkModeListener listener) {
darkModeListener = listener;
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES;

if (darkModeListener != null) {
darkModeListener.onDarkModeChanged(isDarkMode);
}

super.onConfigurationChanged(newConfig);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
Expand Down Expand Up @@ -620,6 +621,28 @@ public void requestPermissions(String[] permissions) {
requestPermissionsWithRequestCode(permissions, 1);
}

public interface DarkModeListener {
void onDarkModeChanged(boolean isDarkMode);
}

private DarkModeListener darkModeListener = null;

public void setDarkModeListener(DarkModeListener listener) {
darkModeListener = listener;
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES;

if (darkModeListener != null) {
darkModeListener.onDarkModeChanged(isDarkMode);
}

super.onConfigurationChanged(newConfig);
}

public static void changeKeyboard(int inputType) {
if (SDLActivity.keyboardInputType != inputType) {
SDLActivity.keyboardInputType = inputType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
Expand Down Expand Up @@ -619,6 +620,28 @@ public void requestPermissions(String[] permissions) {
requestPermissionsWithRequestCode(permissions, 1);
}

public interface DarkModeListener {
void onDarkModeChanged(boolean isDarkMode);
}

private DarkModeListener darkModeListener = null;

public void setDarkModeListener(DarkModeListener listener) {
darkModeListener = listener;
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES;

if (darkModeListener != null) {
darkModeListener.onDarkModeChanged(isDarkMode);
}

super.onConfigurationChanged(newConfig);
}

public static void changeKeyboard(int inputType) {
/*
if (SDLActivity.keyboardInputType != inputType){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
Expand Down Expand Up @@ -547,6 +548,28 @@ public void requestPermissionsWithRequestCode(String[] permissions, int requestC
public void requestPermissions(String[] permissions) {
requestPermissionsWithRequestCode(permissions, 1);
}

public interface DarkModeListener {
void onDarkModeChanged(boolean isDarkMode);
}

private DarkModeListener darkModeListener = null;

public void setDarkModeListener(DarkModeListener listener) {
darkModeListener = listener;
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
int currentNightMode = newConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK;
boolean isDarkMode = currentNightMode == Configuration.UI_MODE_NIGHT_YES;

if (darkModeListener != null) {
darkModeListener.onDarkModeChanged(isDarkMode);
}

super.onConfigurationChanged(newConfig);
}
}

class PythonMain implements Runnable {
Expand Down
57 changes: 57 additions & 0 deletions pythonforandroid/recipes/android/src/android/darkmode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from typing import Callable

from jnius import PythonJavaClass, java_method, autoclass
from android.config import ACTIVITY_CLASS_NAME, ACTIVITY_CLASS_NAMESPACE

_listener = None


class DarkModeListener(PythonJavaClass):
"""
A listener class for detecting and handling dark mode changes.

This class implements the `DarkModeListener` interface in a Python-Java
hybrid context through Kivy Android functionality. It listens for changes
in the system's dark mode settings and executes a callback upon detecting
a change.

Attributes:
on_dark_mode_changed (Callable[[bool], None]): A callback function to
handle the event when dark mode status changes. The callback
receives a single parameter `is_dark_mode`, which is a boolean
indicating whether dark mode is currently enabled.
"""
__javacontext__ = "app"
__javainterfaces__ = [ACTIVITY_CLASS_NAMESPACE + '$DarkModeListener']

def __init__(self, on_dark_mode_changed: Callable[[bool], None]):
self.on_dark_mode_changed = on_dark_mode_changed

@java_method('(Z)V')
def onDarkModeChanged(self, is_dark_mode):
self.on_dark_mode_changed(is_dark_mode)


def set_dark_mode_listener(on_dark_mode_changed: Callable[[bool], None] | None) -> None:
"""
Sets a listener to monitor changes in the dark mode state.

This function assigns a provided callback to handle changes in the
dark mode settings. The callback will be invoked with a boolean
argument indicating the current dark mode state.

Args:
on_dark_mode_changed: A callable that accepts a single boolean
parameter indicating whether dark mode is active.

Returns:
None
"""
global _listener
activity = autoclass(ACTIVITY_CLASS_NAME).mActivity
if on_dark_mode_changed:
_listener = DarkModeListener(on_dark_mode_changed)
activity.setDarkModeListener(_listener)
else:
activity.setDarkModeListener(on_dark_mode_changed)
_listener = None
Loading