initial: oboe, logging

This commit is contained in:
2026-02-01 02:54:05 +01:00
commit 8b6de6a883
45 changed files with 1514 additions and 0 deletions

14
.gitignore vendored Normal file
View File

@@ -0,0 +1,14 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
.externalNativeBuild
/.idea
/app/src/main/libs/
app/src/main/obj/
.cxx
/txts

1
app/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/build

0
app/CMakeLists.txt Normal file
View File

83
app/build.gradle Normal file
View File

@@ -0,0 +1,83 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
namespace 'at.lockstep'
compileSdk 34
defaultConfig {
applicationId "at.lockstep"
minSdk 24
targetSdk 34
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {
useSupportLibrary true
}
externalNativeBuild {
cmake {
//path 'src/main/cpp/CMakeLists.txt'
cppFlags ''
arguments "-DANDROID_STL=c++_shared"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
prefab true
}
composeOptions {
kotlinCompilerExtensionVersion '1.5.1'
}
packaging {
resources {
excludes += '/META-INF/{AL2.0,LGPL2.1}'
}
}
externalNativeBuild {
cmake {
path file('src/main/cpp/CMakeLists.txt')
version '3.22.1'
}
}
}
dependencies {
implementation libs.oboe
implementation libs.slf4j.api
implementation libs.logback.android
implementation libs.androidx.core.ktx
implementation libs.androidx.lifecycle.runtime.ktx
implementation libs.androidx.activity.compose
implementation platform(libs.androidx.compose.bom)
implementation libs.androidx.ui
implementation libs.androidx.ui.graphics
implementation libs.androidx.ui.tooling.preview
implementation libs.androidx.material3
testImplementation libs.junit
androidTestImplementation libs.androidx.junit
androidTestImplementation libs.androidx.espresso.core
androidTestImplementation platform(libs.androidx.compose.bom)
androidTestImplementation libs.androidx.ui.test.junit4
debugImplementation libs.androidx.ui.tooling
debugImplementation libs.androidx.ui.test.manifest
}

21
app/proguard-rules.pro vendored Normal file
View File

@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Lockstep"
tools:targetApi="31">
<activity
android:name="at.lockstep.app.MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Lockstep">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,27 @@
<configuration>
<property name="LOG_DIR" value="/data/data/at.lockstep.app/files" />
<appender name="logcat" class="ch.qos.logback.classic.android.LogcatAppender">
<encoder>
<pattern>%msg</pattern>
</encoder>
</appender>
<!--
<appender name="logfile" class="ch.qos.logback.core.FileAppender">
<file>${LOG_DIR}/debug.log</file>
<encoder>
<pattern>%d{yyyy-MM-dd' 'HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
-->
<root level="DEBUG">
<appender-ref ref="logcat" />
<!-- in other app, detached from MainActivity.onCreate(), unless AppSettings.logfileDebugging = true -->
<!--
<appender-ref ref="logfile" />
-->
</root>
</configuration>

View File

@@ -0,0 +1,48 @@
# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html.
# For more examples on how to use CMake, see https://github.com/android/ndk-samples.
# Sets the minimum CMake version required for this project.
cmake_minimum_required(VERSION 3.22.1)
# Declares the project name. The project name can be accessed via ${ PROJECT_NAME},
# Since this is the top level CMakeLists.txt, the project name is also accessible
# with ${CMAKE_PROJECT_NAME} (both CMake variables are in-sync within the top level
# build script scope).
project("lockstep-native")
# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#
# In this top level CMakeLists.txt, ${CMAKE_PROJECT_NAME} is used to define
# the target library name; in the sub-module's CMakeLists.txt, ${PROJECT_NAME}
# is preferred for the same purpose.
#
# In order to load a library into your app from Java/Kotlin, you must call
# System.loadLibrary() and pass the name of the library defined here;
# for GameActivity/NativeActivity derived applications, the same library name must be
# used in the AndroidManifest.xml file.
add_library(${CMAKE_PROJECT_NAME} SHARED
# List C/C++ source files with relative paths to this CMakeLists.txt.
lockstep.cpp
PlaybackEngine.cpp
)
find_package (oboe REQUIRED CONFIG)
add_library(ndk-logger SHARED logging.cpp logging_jni.cpp)
target_link_libraries(ndk-logger log)
# Specifies libraries CMake should link to your target library. You
# can link libraries from various origins, such as libraries defined in this
# build script, prebuilt third-party libraries, or Android system libraries.
target_link_libraries(${CMAKE_PROJECT_NAME}
# List libraries link to the target library
oboe::oboe
android
log
ndk-logger
)

View File

@@ -0,0 +1,78 @@
//
// Created by david on 01.02.2026.
//
#ifndef LOCKSTEP_OBOESINEPLAYER_H
#define LOCKSTEP_OBOESINEPLAYER_H
#include <oboe/Oboe.h>
#include <math.h>
using namespace oboe;
class OboeSinePlayer: public oboe::AudioStreamDataCallback {
public:
virtual ~OboeSinePlayer() = default;
// Call this from Activity onResume()
int32_t startAudio() {
std::lock_guard<std::mutex> lock(mLock);
oboe::AudioStreamBuilder builder;
// The builder set methods can be chained for convenience.
Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)
->setPerformanceMode(oboe::PerformanceMode::LowLatency)
->setChannelCount(kChannelCount)
->setSampleRate(kSampleRate)
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium)
->setFormat(oboe::AudioFormat::Float)
->setDataCallback(this)
->openStream(mStream);
if (result != Result::OK) return (int32_t) result;
// Typically, start the stream after querying some stream information, as well as some input from the user
result = mStream->requestStart();
return (int32_t) result;
}
// Call this from Activity onPause()
void stopAudio() {
// Stop, close and delete in case not already closed.
std::lock_guard<std::mutex> lock(mLock);
if (mStream) {
mStream->stop();
mStream->close();
mStream.reset();
}
}
oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override {
float *floatData = (float *) audioData;
for (int i = 0; i < numFrames; ++i) {
float sampleValue = kAmplitude * sinf(mPhase);
for (int j = 0; j < kChannelCount; j++) {
floatData[i * kChannelCount + j] = sampleValue;
}
mPhase += mPhaseIncrement;
if (mPhase >= kTwoPi) mPhase -= kTwoPi;
}
return oboe::DataCallbackResult::Continue;
}
private:
std::mutex mLock;
std::shared_ptr<oboe::AudioStream> mStream;
// Stream params
static int constexpr kChannelCount = 2;
static int constexpr kSampleRate = 48000;
// Wave params, these could be instance variables in order to modify at runtime
static float constexpr kAmplitude = 0.5f;
static float constexpr kFrequency = 440;
static float constexpr kPI = M_PI;
static float constexpr kTwoPi = kPI * 2;
static double constexpr mPhaseIncrement = kFrequency * kTwoPi / (double) kSampleRate;
// Keeps track of where the wave is
float mPhase = 0.0;
};
#endif //LOCKSTEP_OBOESINEPLAYER_H

View File

@@ -0,0 +1,24 @@
//
// Created by david on 01.02.2026.
//
#define LOG_TAG "PlaybackEngine"
#include "PlaybackEngine.h"
#include "logging.h"
PlaybackEngine::PlaybackEngine() {
LOGI("PlaybackEngine()");
LOGI("NDK LOG_LEVEL=%d", LOG_LEVEL);
// NDK LOG_LEVEL=3 (DEBUG)
mPlayer = new OboeSinePlayer();
int32_t res = mPlayer->startAudio();
LOGI("startAudio() = %d", res);
}
PlaybackEngine::~PlaybackEngine() {
LOGI("~PlaybackEngine()");
mPlayer->stopAudio();
delete mPlayer;
mPlayer = nullptr;
}

View File

@@ -0,0 +1,18 @@
//
// Created by david on 01.02.2026.
//
#ifndef LOCKSTEP_PLAYBACKENGINE_H
#define LOCKSTEP_PLAYBACKENGINE_H
#include "OboeSinePlayer.h"
class PlaybackEngine {
public:
PlaybackEngine();
virtual ~PlaybackEngine();
private:
OboeSinePlayer *mPlayer;
};
#endif //LOCKSTEP_PLAYBACKENGINE_H

View File

@@ -0,0 +1,54 @@
// Write C++ code here.
//
// Do not forget to dynamically load the C++ library into your application.
//
// For instance,
//
// In at.lockstep.app.MainActivity.java:
// static {
// System.loadLibrary("lockstep");
// }
//
// Or, in at.lockstep.app.MainActivity.kt:
// companion object {
// init {
// System.loadLibrary("lockstep")
// }
// }
#include "PlaybackEngine.h"
#include <jni.h>
#include <oboe/Oboe.h>
extern "C" {
/**
* Creates the audio engine
*
* @return a pointer to the audio engine. This should be passed to other methods
*/
JNIEXPORT jlong JNICALL
Java_at_lockstep_pb_PlaybackEngine_native_1createEngine(
JNIEnv *env,
jclass /*unused*/) {
/*
const char* filesDirTemp = env->GetStringUTFChars(filesDir, NULL);
std::string filesDirString(filesDirTemp);
env->ReleaseStringUTFChars(filesDir, filesDirTemp);
*/
// We use std::nothrow so `new` returns a nullptr if the engine creation fails
auto *engine = new(std::nothrow) PlaybackEngine();
return reinterpret_cast<jlong>(engine);
}
JNIEXPORT void JNICALL
Java_at_lockstep_pb_PlaybackEngine_native_1deleteEngine(
JNIEnv *env,
jclass,
jlong engineHandle) {
delete reinterpret_cast<PlaybackEngine *>(engineHandle);
}
} // extern "C"

View File

@@ -0,0 +1,154 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Logger implement, support writing into stdout and send for java logback
*/
#include "logging.h"
#include <android/log.h>
extern "C" {
static JavaVM * __logback_jvm = NULL;
static jclass __logback_jclass_logger;
static jmethodID __logback_jmethod_logWrite;
void
__stdout_log_print(const int level, const char * format, ...)
{
va_list args;
static char tags[] = {'?', '?', 'V', 'D', 'I', 'W', 'E', 'F', '?'};
va_start(args, format);
printf("[%c]%s ", tags[level], LOG_TAG);
vprintf(format, args);
printf("\n");
va_end(args);
}
void
__stdout_log_vprint(const int level, const char * format, va_list ap)
{
static char tags[] = {'?', '?', 'V', 'D', 'I', 'W', 'E', 'F', '?'};
printf("[%c]%s ", tags[level], LOG_TAG);
vprintf(format, ap);
printf("\n");
}
void
__stdout_log_write(const int level, const char * msg)
{
static char tags[] = {'?', '?', 'V', 'D', 'I', 'W', 'E', 'F', '?'};
printf("[%c]%s %s\n", tags[level], LOG_TAG, msg);
}
void
logback_init(JavaVM * jVM, JNIEnv * env)
{
__logback_jvm = jVM;
jclass jclass_logger = env->FindClass("com/rex/logger/NdkLogger");
if (! jclass_logger) {
__android_log_write(LOG_LEVEL_ERROR, LOG_TAG, "logback_init failed to get logger class reference");
return;
}
__logback_jclass_logger = (jclass) env->NewGlobalRef(jclass_logger);
__logback_jmethod_logWrite = env->GetStaticMethodID(__logback_jclass_logger, "logWrite", "(ILjava/lang/String;)V");
if (! __logback_jmethod_logWrite) {
__android_log_write(LOG_LEVEL_ERROR, LOG_TAG, "logback_init failed to get logwrite method ID");
return;
}
}
void
logback_uninit(JNIEnv * env)
{
env->DeleteGlobalRef(__logback_jclass_logger);
__logback_jclass_logger = NULL;
}
void
__logback_print(const int level, const char * format, ...)
{
JNIEnv * env = NULL;
jint err = JNI_OK;
if (! __logback_jvm) return;
if (JNI_EDETACHED == (err = __logback_jvm->GetEnv((void**) &env, JNI_VERSION_1_4))) {
if (__logback_jvm->AttachCurrentThread(&env, NULL) < 0) {
__android_log_write(LOG_LEVEL_WARN, LOG_TAG, "__logback_write failed to get env neither attach current thread");
}
}
static char buffer[1024];
va_list args;
va_start(args, format);
vsnprintf(buffer, sizeof(buffer), format, args);
jstring jmsg = env->NewStringUTF(buffer);
env->CallStaticVoidMethod(__logback_jclass_logger, __logback_jmethod_logWrite, level, jmsg);
env->DeleteLocalRef(jmsg);
va_end(args);
if (JNI_EDETACHED == err) __logback_jvm->DetachCurrentThread();
}
void
__logback_vprint(const int level, const char * format, va_list ap)
{
JNIEnv * env = NULL;
jint err = JNI_OK;
if (! __logback_jvm) return;
if (JNI_EDETACHED == (err = __logback_jvm->GetEnv((void**) &env, JNI_VERSION_1_4))) {
if (__logback_jvm->AttachCurrentThread(&env, NULL) < 0) {
__android_log_write(LOG_LEVEL_WARN, LOG_TAG, "__logback_write failed to get env neither attach current thread");
}
}
static char buffer[1024];
vsnprintf(buffer, sizeof(buffer), format, ap);
jstring jmsg = env->NewStringUTF(buffer);
env->CallStaticVoidMethod(__logback_jclass_logger, __logback_jmethod_logWrite, level, jmsg);
env->DeleteLocalRef(jmsg);
if (JNI_EDETACHED == err) __logback_jvm->DetachCurrentThread();
}
void
__logback_write(const int level, const char * msg)
{
JNIEnv * env = NULL;
jint err = JNI_OK;
if (! __logback_jvm) return;
if (JNI_EDETACHED == (err = __logback_jvm->GetEnv((void**) &env, JNI_VERSION_1_4))) {
if (__logback_jvm->AttachCurrentThread(&env, NULL) < 0) {
__android_log_write(LOG_LEVEL_WARN, LOG_TAG, "__logback_write failed to get env neither attach current thread");
}
}
jstring jmsg = env->NewStringUTF(msg);
env->CallStaticVoidMethod(__logback_jclass_logger, __logback_jmethod_logWrite, level, jmsg);
env->DeleteLocalRef(jmsg);
if (JNI_EDETACHED == err) __logback_jvm->DetachCurrentThread();
}
}
// vim:ts=8:sw=4:

119
app/src/main/cpp/logging.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Logging support, provide the level definition and support logging to logcat, stdout and Java logback
* When using logback, need add com/rex/logger/NdkLogger.java into project
*/
#ifndef _LOGGING_H_
#define _LOGGING_H_
#define LOG_OUTPUT_LOGBACK
#ifndef LOG_TAG
# define LOG_TAG "Rex"
#endif
#ifndef LOG_LEVEL
# define LOG_LEVEL LOG_LEVEL_DEBUG
//# define LOG_LEVEL LOG_LEVEL_VERBOSE // note: goes to logcat only
#endif
// values here must match those in android_LogPriority
#define LOG_LEVEL_ALL 1
#define LOG_LEVEL_VERBOSE 2
#define LOG_LEVEL_DEBUG 3
#define LOG_LEVEL_INFO 4
#define LOG_LEVEL_WARN 5
#define LOG_LEVEL_ERROR 6
#define LOG_LEVEL_FATAL 7
#define LOG_LEVEL_SILENT 8
#include <stdio.h>
#include <stdarg.h>
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
void __stdout_log_print(const int level, const char * format, ...);
void __stdout_log_vprint(const int level, const char * format, va_list ap);
void __stdout_log_write(const int level, const char * msg);
void logback_init(JavaVM * jVM, JNIEnv * env);
void logback_uninit(JNIEnv * env);
void __logback_print(const int level, const char * format, ...);
void __logback_vprint(const int level, const char * format, va_list ap);
void __logback_write(const int level, const char * msg);
#ifdef __cplusplus
} //extern "C"
#endif
#ifdef LOG_OUTPUT_STDOUT
# define LOG_PRINT(prio, format, ...) __stdout_log_print(prio, format, ##__VA_ARGS__)
# define LOG_VPRINT(prio, format, ap) __stdout_log_vprint(prio, format, ap)
# define LOG_WRITE(prio, msg) __stdout_log_write(prio, msg)
#elif defined(LOG_OUTPUT_LOGBACK)
# define LOG_PRINT(prio, format, ...) __logback_print(prio, LOG_TAG " - " format, ##__VA_ARGS__)
# define LOG_VPRINT(prio, format, ap) __logback_vprint(prio, LOG_TAG " - " format, ap)
# define LOG_WRITE(prio, msg) __logback_write(prio, LOG_TAG " - " msg)
# include <android/log.h>
# define LOG_PRINT_ANDROID(prio, format, ...) __android_log_print(prio, LOG_TAG, format, ##__VA_ARGS__)
#else
# include <android/log.h>
# define LOG_PRINT(prio, format, ...) __android_log_print(prio, LOG_TAG, format, ##__VA_ARGS__)
# define LOG_VPRINT(prio, format, ap) __android_log_vprint(prio, LOG_TAG, format, ap)
# define LOG_WRITE(prio, msg) __android_log_write(prio, LOG_TAG, msg)
#endif
#if LOG_LEVEL > LOG_LEVEL_VERBOSE
# define LOGV(...)
#else
# define LOGV(...) LOG_PRINT_ANDROID(LOG_LEVEL_VERBOSE, __VA_ARGS__)
#endif
#if LOG_LEVEL > LOG_LEVEL_DEBUG
# define LOGD(...)
#else
# define LOGD(...) LOG_PRINT(LOG_LEVEL_DEBUG, __VA_ARGS__)
#endif
#if LOG_LEVEL > LOG_LEVEL_INFO
# define LOGI(...)
#else
# define LOGI(...) LOG_PRINT(LOG_LEVEL_INFO, __VA_ARGS__)
#endif
#if LOG_LEVEL > LOG_LEVEL_WARN
# define LOGW(...)
#else
# define LOGW(...) LOG_PRINT(LOG_LEVEL_WARN, __VA_ARGS__)
#endif
#if LOG_LEVEL > LOG_LEVEL_ERROR
# define LOGE(...)
#else
# define LOGE(...) LOG_PRINT(LOG_LEVEL_ERROR, __VA_ARGS__)
#endif
#endif /* #ifndef _LOGGING_H_ */
// vim:ts=8:sw=4:

View File

@@ -0,0 +1,93 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <string.h>
#include <jni.h>
#include "logging.h"
extern "C" jstring
Java_com_rex_logger_NdkLogger_native_1getABI(JNIEnv* env, jclass thiz)
{
#if defined(__arm__)
#if defined(__ARM_ARCH_7A__)
#if defined(__ARM_NEON__)
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a/NEON (hard-float)"
#else
#define ABI "armeabi-v7a/NEON"
#endif
#else
#if defined(__ARM_PCS_VFP)
#define ABI "armeabi-v7a (hard-float)"
#else
#define ABI "armeabi-v7a"
#endif
#endif
#else
#define ABI "armeabi"
#endif
#elif defined(__i386__)
#define ABI "x86"
#elif defined(__x86_64__)
#define ABI "x86_64"
#elif defined(__mips64) /* mips64el-* toolchain defines __mips__ too */
#define ABI "mips64"
#elif defined(__mips__)
#define ABI "mips"
#elif defined(__aarch64__)
#define ABI "arm64-v8a"
#else
#define ABI "unknown"
#endif
return env->NewStringUTF(ABI);
}
extern "C" jint
JNI_OnLoad(JavaVM * vm, void * reserved)
{
JNIEnv * env = NULL;
jclass clazz;
//LOGV("JNI_Onload vm:%p reserved:%p", vm, reserved);
if (JNI_OK != vm->GetEnv((void**) &env, JNI_VERSION_1_4)) {
//LOGE("JNI_OnUnload GetEnv JNI_VERSION_1_4 failed");
return JNI_VERSION_1_4;
}
logback_init(vm, env);
return JNI_VERSION_1_4;
}
extern "C" void
JNI_OnUnload(JavaVM * vm, void * reserved)
{
JNIEnv * env = NULL;
//LOGV("JNI_OnUnload vm:%p reserved:%p", vm, reserved);
if (JNI_OK != vm->GetEnv((void**) &env, JNI_VERSION_1_4)) {
//LOGE("JNI_OnUnload GetEnv JNI_VERSION_1_4 failed");
return;
}
logback_uninit(env);
}
// vim:ts=8:sw=4:

View File

@@ -0,0 +1,23 @@
package at.lockstep.app;
import android.app.Activity;
import at.lockstep.pb.PlaybackEngine;
public class MainActivity extends Activity {
/*
* Creating engine in onResume() and destroying in onPause() so the stream retains exclusive
* mode only while in focus. This allows other apps to reclaim exclusive stream mode.
*/
@Override
protected void onResume() {
super.onResume();
PlaybackEngine.create(this); // note: called twice (is permission request causing Activity to go out of focus?)
}
@Override
protected void onPause() {
PlaybackEngine.delete();
super.onPause();
}
}

View File

@@ -0,0 +1,31 @@
package at.lockstep.pb;
import android.content.Context;
import android.util.Log;
public class PlaybackEngine {
static long mEngineHandle = 0;
static {
System.loadLibrary("lockstep-native");
}
public static boolean create(Context context) {
if (mEngineHandle == 0) {
//setDefaultStreamValues(context); // TODO
Log.i("PlaybackEngine", "Hello PlaybackEngine");
mEngineHandle = native_createEngine();
}
return (mEngineHandle != 0);
}
public static void delete() {
if (mEngineHandle != 0){
native_deleteEngine(mEngineHandle);
}
mEngineHandle = 0;
}
private static native long native_createEngine();
private static native void native_deleteEngine(long engineHandle);
}

View File

@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.rex.logger;
import android.util.Log;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import proguard.annotation.KeepName;
//@KeepName
/**
* Gather native log into logback, for easy control save log into SDCard
*/
public class NdkLogger {
private static final Logger sLogger = LoggerFactory.getLogger("NDK");
//@KeepName
public static void logWrite(int level, String message) {
//sLogger.trace("level:{} message:{}", level, message);
switch (level) {
case Log.VERBOSE:
sLogger.trace(message);
break;
case Log.DEBUG:
sLogger.debug(message);
break;
case Log.INFO:
sLogger.info(message);
break;
case Log.WARN:
sLogger.warn(message);
break;
case Log.ERROR:
sLogger.error(message);
break;
}
}
static {
try {
System.loadLibrary("ndk-logger");
} catch (UnsatisfiedLinkError ex) {
sLogger.error("Failed to load library.", ex);
}
}
public static String getABI() { return native_getABI(); }
private static native String native_getABI();
}

View File

@@ -0,0 +1,170 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#3DDC84"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeWidth="0.8"
android:strokeColor="#33FFFFFF" />
</vector>

View File

@@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="purple_200">#FFBB86FC</color>
<color name="purple_500">#FF6200EE</color>
<color name="purple_700">#FF3700B3</color>
<color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
</resources>

View File

@@ -0,0 +1,3 @@
<resources>
<string name="app_name">Lockstep</string>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Lockstep" parent="android:Theme.Material.Light.NoActionBar" />
</resources>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample backup rules file; uncomment and customize as necessary.
See https://developer.android.com/guide/topics/data/autobackup
for details.
Note: This file is ignored for devices older that API 31
See https://developer.android.com/about/versions/12/backup-restore
-->
<full-backup-content>
<!--
<include domain="sharedpref" path="."/>
<exclude domain="sharedpref" path="device.xml"/>
-->
</full-backup-content>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
Sample data extraction rules file; uncomment and customize as necessary.
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
for details.
-->
<data-extraction-rules>
<cloud-backup>
<!-- TODO: Use <include> and <exclude> to control what is backed up.
<include .../>
<exclude .../>
-->
</cloud-backup>
<!--
<device-transfer>
<include .../>
<exclude .../>
</device-transfer>
-->
</data-extraction-rules>

5
build.gradle Normal file
View File

@@ -0,0 +1,5 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false
}

23
gradle.properties Normal file
View File

@@ -0,0 +1,23 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. For more details, visit
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true

37
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,37 @@
[versions]
agp = "8.6.0"
kotlin = "1.9.0"
coreKtx = "1.10.1"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
lifecycleRuntimeKtx = "2.6.1"
activityCompose = "1.9.3"
composeBom = "2024.04.01"
logbackAndroid = "2.0.0"
oboe = "1.10.0"
slf4jApi = "1.7.30"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "composeBom" }
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
logback-android = { module = "com.github.tony19:logback-android", version.ref = "logbackAndroid" }
oboe = { module = "com.google.oboe:oboe", version.ref = "oboe" }
slf4j-api = { module = "org.slf4j:slf4j-api", version.ref = "slf4jApi" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,6 @@
#Sun Feb 01 01:13:22 CET 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
gradlew vendored Normal file
View File

@@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
gradlew.bat vendored Normal file
View File

@@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

23
settings.gradle Normal file
View File

@@ -0,0 +1,23 @@
pluginManagement {
repositories {
google {
content {
includeGroupByRegex("com\\.android.*")
includeGroupByRegex("com\\.google.*")
includeGroupByRegex("androidx.*")
}
}
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
}
}
rootProject.name = "Lockstep"
include ':app'