// -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-

// Version: MPL 1.1 / GPLv3+ / LGPLv3+
//
// The contents of this file are subject to the Mozilla Public License Version
// 1.1 (the "License"); you may not use this file except in compliance with
// the License or as specified alternatively below. You may obtain a copy of
// the License at http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// Major Contributor(s):
// Copyright (C) 2011 Tor Lillqvist <tml@iki.fi> (initial developer)
// Copyright (C) 2011 SUSE Linux http://suse.com (initial developer's employer)
//
// All Rights Reserved.
//
// For minor contributions see the git repository.
//
// Alternatively, the contents of this file may be used under the terms of
// either the GNU General Public License Version 3 or later (the "GPLv3+"), or
// the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"),
// in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable
// instead of those above.

package org.libreoffice.android;

import android.app.Activity;
import android.app.NativeActivity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;

import fi.iki.tml.CommandLine;

import java.io.File;
import java.util.Arrays;
import java.util.Scanner;

// We override NativeActivity so that we can get at the intent of the
// activity and its extra parameters, that we use to tell us what
// actual LibreOffice "program" to run. I.e. something that on desktop
// OSes would be a program, but for Androis is actually built as a
// shared object, with an "lo_main" function.

public class Bootstrap extends NativeActivity
{
    private static String TAG = "lo-bootstrap";

    private static native boolean setup(String dataDir,
                                        String apkFile,
                                        String[] ld_library_path);

    public static native boolean setup(int lo_main_ptr,
                                       Object lo_main_argument,
                                       int lo_main_delay);

    // This is not just a wrapper for the C library dlopen(), but also
    // loads recursively dependent libraries.
    public static native int dlopen(String library);

    // This is just a wrapper for the C library dlsym().
    public static native int dlsym(int handle, String symbol);

    // To be called after you are sure libgnustl_shared.so
    // has been loaded
    public static native void patch_libgnustl_shared();

    // Wrapper for getpid()
    public static native int getpid();

    // Wrapper for system()
    public static native void system(String cmdline);

    // Wrapper for putenv()
    public static native void putenv(String string);

    public static void setup(Activity activity)
    {
        String dataDir = null;

        ApplicationInfo ai = activity.getApplicationInfo();
        dataDir = ai.dataDir;
        Log.i(TAG, String.format("dataDir=%s\n", dataDir));

        String llp = System.getenv("LD_LIBRARY_PATH");
        if (llp == null)
            llp = "/vendor/lib:/system/lib";

        String[] llpa = llp.split(":");

        if (!setup(dataDir, activity.getApplication().getPackageResourcePath(), llpa))
            return;

    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        setup(this);

        String mainLibrary = getIntent().getStringExtra("lo-main-library");

        if (mainLibrary == null)
            mainLibrary = "libcppunittester";

        mainLibrary += ".so";

        Log.i(TAG, String.format("mainLibrary=%s", mainLibrary));

        // Get "command line" to pass to the LO "program"
        String cmdLine = getIntent().getStringExtra("lo-main-cmdline");

        if (cmdLine == null) {
            String indirectFile = getIntent().getStringExtra("lo-main-indirect-cmdline");

            if (indirectFile != null) {
                try {
                    // Somewhat stupid but short way to read a file into a string
                    cmdLine = new Scanner(new File(indirectFile), "UTF-8").useDelimiter("\\A").next().trim();
                }
                catch (java.io.FileNotFoundException e) {
                    Log.i(TAG, String.format("Could not read %s: %s",indirectFile, e.toString()));
                }
            }

            if (cmdLine == null)
                cmdLine = "/data/data/org.libreoffice.android/lib/libqa_sal_types.so";
        }

        Log.i(TAG, String.format("cmdLine=%s", cmdLine));

        String[] argv = CommandLine.split(cmdLine);

        // Handle env var assignments in the command line.
        while (argv.length > 0 &&
               argv[0].matches("[A-Z_]+=.*")) {
            putenv(argv[0]);
            argv = Arrays.copyOfRange(argv, 1, argv.length-1);
        }

        // TMPDIR is used by osl_getTempDirURL()
        putenv("TMPDIR=" + getCacheDir().getAbsolutePath());

        // argv[0] will be replaced by android_main() in lo-bootstrap.c by the
        // pathname of the mainLibrary.
        String[] newargv = new String[argv.length + 1];
        newargv[0] = "dummy-program-name";
        System.arraycopy(argv, 0, newargv, 1, argv.length);
        argv = newargv;

        // Load the LO "program" here and look up lo_main
        int loLib = dlopen(mainLibrary);

        if (loLib == 0) {
            Log.i(TAG, String.format("Could not load %s", mainLibrary));
            return;
        }

        int lo_main = dlsym(loLib, "lo_main");
        if (lo_main == 0) {
            Log.i(TAG, String.format("No lo_main in %s", mainLibrary));
            return;
        }

        // Start a strace on ourself if requested.

        // Note that the started strace will have its stdout and
        // stderr connected to /dev/null, so you definitely want to
        // specify an -o option in the lo-strace extra. Also, strace
        // will trace only *this* thread, which is not the one that
        // eventually will run android_main() and lo_main(), so you
        // also want the -f option.
        String strace_args = getIntent().getStringExtra("lo-strace");
        if (strace_args != null)
            system("/system/xbin/strace -p " + getpid() + " " + (strace_args != "yes" ? strace_args : "" ) + " &");

        int delay = 0;
        String sdelay = getIntent().getStringExtra("lo-main-delay");
        if (sdelay != null)
            delay = Integer.parseInt(sdelay);

        // Tell lo-bootstrap.c the stuff it needs to know
        if (!setup(lo_main, argv, delay))
            return;

        // Finally, call our super-class, NativeActivity's onCreate(),
        // which eventually calls the ANativeActivity_onCreate() in
        // android_native_app_glue.c, which starts a thread in which
        // android_main() from lo-bootstrap.c is called.

        // android_main() calls the lo_main() defined in sal/main.h
        // through the function pointer passed to setup() above, with
        // the argc and argv also saved from the setup() call.
        super.onCreate(savedInstanceState);
    }

    // This is used to load the 'lo-bootstrap' library on application
    // startup. The library has already been unpacked into
    // /data/data/<app name>/lib/liblo-bootstrap.so at installation
    // time by the package manager.
    static {
        System.loadLibrary("lo-bootstrap");
    }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

@@ -1579,16 +1579,14 @@
  We 
-override
+extend
  Nat
@@ -1816,17 +1816,17 @@
 r Androi
-s
+d
  is actu
@@ -1865,17 +1865,16 @@
 , with a
-n
  %22lo_mai

Edit a comment a bit