Describe the bug
I need a permanent floating window, so I need to use a service to implement it, not an activity (toga can be called normally,so to prove that the software environment is fine)
FloatingWindowService.java:
package org.beeware.android;
import static android.content.ContentValues.TAG;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.MenuItem;
import android.view.Menu;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.Nullable;
import java.util.Arrays;
import java.util.Objects;
import com.chaquo.python.Kwarg;
import com.chaquo.python.PyException;
import com.chaquo.python.Python;
import com.chaquo.python.PyObject;
import com.chaquo.python.android.AndroidPlatform;
import com.example.uiapp.R;
public class FloatingWindowService extends Service {
public static final String TAG = "FloatingWindowService";
private WindowManager windowManager;
private ViewGroup floatView;
private int LAYOUT_TYPE;
private WindowManager.LayoutParams floatWindowLayoutParam;
private static PyObject pythonApp;
@SuppressWarnings("unused")
public static void setPythonApp(IPythonApp app) {
pythonApp = PyObject.fromJava(app);
}
public void onCreate() {
super.onCreate();
Log.d(TAG, "FloatingWindowService onCreate()");
updateFloatingWindowContent(null);
//createFloatingWindow();
//startTogaActivity();
userCode("onCreate");
}
private void updateFloatingWindowContent(TextView textView) {
// Make sure Python is initialized
if (!Python.isStarted()) {
AndroidPlatform platform = new AndroidPlatform(this);
platform.redirectStdioToLogcat();
Python.start(platform);
}
Python py = Python.getInstance();
Log.d(TAG, "Running Python code to update floating window content");
// Call Python function to get content
py.getModule("runpy").callAttr(
"run_module",
"uiapp.__main__",
new Kwarg("run_name", "__main__"),
new Kwarg("alter_sys", true)
);
// Update the view (run on UI thread)
//textView.post(() -> textView.setText(content));
}
private void startTogaActivity() {
Intent intent = new Intent(this, TogaActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
private int mScreenWidth;
private int mScreenHeight;
private void createFloatingWindow() {
LayoutInflater inflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
floatView = (ViewGroup) inflater.inflate(R.layout.activity_main, null);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_TOAST;
}
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
DisplayMetrics metrics = new DisplayMetrics();
windowManager.getDefaultDisplay().getMetrics(metrics);
mScreenWidth = metrics.widthPixels;
mScreenHeight = 200;
// Determine the correct window type
WindowManager.LayoutParams layoutParams;
if (android.os.Build.VERSION.SDK_INT >= 26) {
// For Android 8.0 and above
layoutParams = new WindowManager.LayoutParams(
mScreenWidth,
mScreenHeight,
LAYOUT_TYPE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
android.graphics.PixelFormat.TRANSLUCENT
);
} else {
// For below Android 8.0
layoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
android.graphics.PixelFormat.TRANSLUCENT
);
}
layoutParams.gravity = Gravity.TOP | Gravity.CENTER;
layoutParams.x = 0;
layoutParams.y = 0;
// Create a placeholder view
TextView textView = new TextView(this);
textView.setText("Loading...");
// Add the view to the window
windowManager.addView(textView, layoutParams);
Log.d(TAG, "Add the view to the window");
// Initialize Python and request content
updateFloatingWindowContent(textView);
}
MediaProjectionManager mediaProjectionManager;
MediaProjection mMediaProjection;
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
createNotificationChannel();
int mResultCode = intent.getIntExtra("code", -1);
Intent mResultData = intent.getParcelableExtra("data");
mediaProjectionManager = (MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE);
mMediaProjection = mediaProjectionManager.getMediaProjection(mResultCode, Objects.requireNonNull(mResultData));
Log.e(TAG, "mMediaProjection created: " + mMediaProjection);
return super.onStartCommand(intent, flags, startId);
}
private void createNotificationChannel() {
Notification.Builder builder = new Notification.Builder(this.getApplicationContext());
Intent nfIntent = new Intent(this, MainActivity.class);
builder.setContentIntent(PendingIntent.getActivity(this, 0, nfIntent, PendingIntent.FLAG_IMMUTABLE))
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.mipmap.ic_launcher))
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText("is running......")
.setWhen(System.currentTimeMillis());
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
builder.setChannelId("notification_id");
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel("notification_id", "notification_name", NotificationManager.IMPORTANCE_LOW);
notificationManager.createNotificationChannel(channel);
}
Notification notification = builder.build();
notification.defaults = Notification.DEFAULT_SOUND;
startForeground(110, notification);
}
public void onConfigurationChanged(Configuration newConfig) {
Log.d(TAG, "onConfigurationChanged() start");
super.onConfigurationChanged(newConfig);
userCode("onConfigurationChanged", newConfig);
Log.d(TAG, "onConfigurationChanged() complete");
}
public boolean onOptionsItemSelected(MenuItem menuitem) {
Log.d(TAG, "onOptionsItemSelected() start");
PyObject pyResult = userCode("onOptionsItemSelected", menuitem);
boolean result = (pyResult == null) ? false : pyResult.toBoolean();
Log.d(TAG, "onOptionsItemSelected() complete");
return result;
}
public boolean onPrepareOptionsMenu(Menu menu) {
Log.d(TAG, "onPrepareOptionsMenu() start");
PyObject pyResult = userCode("onPrepareOptionsMenu", menu);
boolean result = (pyResult == null) ? false : pyResult.toBoolean();
Log.d(TAG, "onPrepareOptionsMenu() complete");
return result;
}
private PyObject userCode(String methodName, Object... args) {
if (pythonApp == null) {
// Could be a non-graphical app such as Python-support-testbed.
return null;
}
try {
if (pythonApp.containsKey(methodName)) {
return pythonApp.callAttr(methodName, args);
} else {
// Handle the case where the method doesn't exist
return null;
}
} catch (PyException e) {
if (e.getMessage().startsWith("NotImplementedError")) {
return null;
}
throw e;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Steps to reproduce
- briefcase run android -d emulator-5554
- Go to app
- Click on 'button'
- See error on console
Expected behavior
a permanent floating window by toga
Screenshots

Environment
- Operating System: windows 10.0.17763.316
- Python version: 3.11.2
- Software versions:
- Briefcase: 0.3.18
- Toga: 0.4.5
- ...
Logs
�[38;5;75mD/FloatingWindowService: Running Python code to update floating window content�[0m
�[38;5;40mI/python.stdout: WARNING: Can't find app icon; falling back to default icon�[0m
�[38;5;166mW/m.example.uiap: Accessing hidden method Ljava/io/FileDescriptor;->setInt$(I)V (greylist,core-platform-api, JNI, allowed)�[0m
�[38;5;166mW/m.example.uiap: Accessing hidden method Landroid/os/Handler;->(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V (greylist, JNI, allowed)�[0m
�[38;5;166mW/m.example.uiap: Accessing hidden method Landroid/os/Handler;->(Z)V (greylist, JNI, allowed)�[0m
�[38;5;40mI/python.stdout: Python app launched & stored in Android Activity class�[0m
�[38;5;75mD/skia : --- Failed to create image decoder with message 'unimplemented'�[0m
Additional context
No response
Describe the bug
I need a permanent floating window, so I need to use a service to implement it, not an activity (toga can be called normally,so to prove that the software environment is fine)
FloatingWindowService.java:
package org.beeware.android;
import static android.content.ContentValues.TAG;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.MenuItem;
import android.view.Menu;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.Nullable;
import java.util.Arrays;
import java.util.Objects;
import com.chaquo.python.Kwarg;
import com.chaquo.python.PyException;
import com.chaquo.python.Python;
import com.chaquo.python.PyObject;
import com.chaquo.python.android.AndroidPlatform;
import com.example.uiapp.R;
public class FloatingWindowService extends Service {
}
Steps to reproduce
Expected behavior
a permanent floating window by toga
Screenshots
Environment
Logs
�[38;5;75mD/FloatingWindowService: Running Python code to update floating window content�[0m
�[38;5;40mI/python.stdout: WARNING: Can't find app icon; falling back to default icon�[0m
�[38;5;166mW/m.example.uiap: Accessing hidden method Ljava/io/FileDescriptor;->setInt$(I)V (greylist,core-platform-api, JNI, allowed)�[0m
�[38;5;166mW/m.example.uiap: Accessing hidden method Landroid/os/Handler;->(Landroid/os/Looper;Landroid/os/Handler$Callback;Z)V (greylist, JNI, allowed)�[0m
�[38;5;166mW/m.example.uiap: Accessing hidden method Landroid/os/Handler;->(Z)V (greylist, JNI, allowed)�[0m
�[38;5;40mI/python.stdout: Python app launched & stored in Android Activity class�[0m
�[38;5;75mD/skia : --- Failed to create image decoder with message 'unimplemented'�[0m
Additional context
No response