/* 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);
}
};