/* Communication module for Android terminals. -*- c-file-style: "GNU" -*- Copyright (C) 2023 Free Software Foundation, Inc. This file is part of GNU Emacs. GNU Emacs is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNU Emacs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ package org.gnu.emacs; import java.io.IOException; import java.util.List; import java.util.ArrayList; import android.graphics.Canvas; import android.graphics.Bitmap; import android.graphics.Point; import android.view.View; import android.annotation.TargetApi; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.res.AssetManager; import android.os.Build; import android.os.Looper; import android.os.IBinder; import android.os.Handler; import android.util.Log; import android.util.DisplayMetrics; class Holder { T thing; }; /* EmacsService is the service that starts the thread running Emacs and handles requests by that Emacs instance. */ public class EmacsService extends Service { public static final String TAG = "EmacsService"; public static final int MAX_PENDING_REQUESTS = 256; public static volatile EmacsService SERVICE; private EmacsThread thread; private Handler handler; /* Display metrics used by font backends. */ public DisplayMetrics metrics; @Override public int onStartCommand (Intent intent, int flags, int startId) { return START_NOT_STICKY; } @Override public IBinder onBind (Intent intent) { return null; } @TargetApi (Build.VERSION_CODES.GINGERBREAD) String getLibraryDirectory () { int apiLevel; Context context; context = getApplicationContext (); apiLevel = Build.VERSION.SDK_INT; if (apiLevel >= Build.VERSION_CODES.GINGERBREAD) return context.getApplicationInfo().nativeLibraryDir; else if (apiLevel >= Build.VERSION_CODES.DONUT) return context.getApplicationInfo().dataDir + "/lib"; return "/data/data/" + context.getPackageName() + "/lib"; } @Override public void onCreate () { AssetManager manager; Context app_context; String filesDir, libDir; double pixelDensityX; double pixelDensityY; SERVICE = this; handler = new Handler (Looper.getMainLooper ()); manager = getAssets (); app_context = getApplicationContext (); metrics = getResources ().getDisplayMetrics (); pixelDensityX = metrics.xdpi; pixelDensityY = metrics.ydpi; try { /* Configure Emacs with the asset manager and other necessary parameters. */ filesDir = app_context.getFilesDir ().getCanonicalPath (); libDir = getLibraryDirectory (); Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir + " and libDir = " + libDir); EmacsNative.setEmacsParams (manager, filesDir, libDir, (float) pixelDensityX, (float) pixelDensityY, this); /* Start the thread that runs Emacs. */ thread = new EmacsThread (this); thread.start (); } catch (IOException exception) { EmacsNative.emacsAbort (); return; } } /* Functions from here on must only be called from the Emacs thread. */ void runOnUiThread (Runnable runnable) { handler.post (runnable); } EmacsView getEmacsView (final EmacsWindow window, final int visibility, final boolean isFocusedByDefault) { Runnable runnable; final Holder view; view = new Holder (); runnable = new Runnable () { public void run () { synchronized (this) { view.thing = new EmacsView (window); view.thing.setVisibility (visibility); view.thing.setFocusedByDefault (isFocusedByDefault); notify (); } } }; synchronized (runnable) { runOnUiThread (runnable); try { runnable.wait (); } catch (InterruptedException e) { EmacsNative.emacsAbort (); } } return view.thing; } public void fillRectangle (EmacsDrawable drawable, EmacsGC gc, int x, int y, int width, int height) { EmacsFillRectangle.perform (drawable, gc, x, y, width, height); } public void fillPolygon (EmacsDrawable drawable, EmacsGC gc, Point points[]) { EmacsFillPolygon.perform (drawable, gc, points); } public void drawRectangle (EmacsDrawable drawable, EmacsGC gc, int x, int y, int width, int height) { EmacsDrawRectangle.perform (drawable, gc, x, y, width, height); } public void drawLine (EmacsDrawable drawable, EmacsGC gc, int x, int y, int x2, int y2) { EmacsDrawLine.perform (drawable, gc, x, y, x2, y2); } public void drawPoint (EmacsDrawable drawable, EmacsGC gc, int x, int y) { EmacsDrawPoint.perform (drawable, gc, x, y); } public void copyArea (EmacsDrawable srcDrawable, EmacsDrawable dstDrawable, EmacsGC gc, int srcX, int srcY, int width, int height, int destX, int destY) { EmacsCopyArea.perform (srcDrawable, gc, dstDrawable, srcX, srcY, width, height, destX, destY); } public void clearWindow (EmacsWindow window) { window.clearWindow (); } public void clearArea (EmacsWindow window, int x, int y, int width, int height) { window.clearArea (x, y, width, height); } };