Skip to content

Commit

Permalink
First public release
Browse files Browse the repository at this point in the history
  • Loading branch information
akulinchev committed Aug 19, 2024
0 parents commit 96a5827
Show file tree
Hide file tree
Showing 125 changed files with 13,550 additions and 0 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.gradle/
/.idea/
/app/debug/
/app/release/
/local.properties
build/
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import me.testcase.ognarviewer.GenerateDdbTask;

plugins {
alias(libs.plugins.androidApplication)
id "androidx.navigation.safeargs"
id "checkstyle"
}

android {
namespace "me.testcase.ognarviewer"
compileSdk 34

defaultConfig {
applicationId "me.testcase.ognarviewer"
minSdk 26
targetSdk 34
versionCode 17
versionName "1.0.0"

resConfigs "en"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
debug {
applicationIdSuffix ".debug"
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
}
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

buildFeatures {
viewBinding true
buildConfig true
}

testOptions {
unitTests {
includeAndroidResources = true
all {
// Otherwise the PrivateDirectoryTest fails.
// See https://github.com/robolectric/robolectric/issues/7456#issuecomment-2089850157
jvmArgs "--add-opens=java.base/java.io=ALL-UNNAMED"
}
}
}

applicationVariants.configureEach { variant ->
variant.registerGeneratedResFolders(project.files(generateDdbResource.outputDirectory).builtBy(generateDdbResource))
}
}

dependencies {
implementation libs.appcompat
implementation libs.constraintlayout
implementation libs.material
implementation libs.navigation.fragment
implementation libs.navigation.ui
implementation libs.preference
implementation libs.recyclerview
implementation libs.recyclerview.selection

debugImplementation libs.leakcanary

testImplementation libs.junit
testImplementation libs.robolectric
}

tasks.register("generateDdbResource", GenerateDdbTask)

// The Checkstyle plugin doesn't work well with the Android plugin => register the task manually.
tasks.register("checkstyle", Checkstyle) {
group "verification"
source "src/main/java"
classpath = files()
}

check.dependsOn("checkstyle")
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
46 changes: 46 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-feature android:name="android.hardware.camera" /><!-- Back (world-facing) camera. -->
<uses-feature android:name="android.hardware.location.gps" />
<uses-feature android:name="android.hardware.sensor.accelerometer" />
<uses-feature android:name="android.hardware.sensor.compass" /><!-- Magnetometer. -->
<uses-feature android:name="android.hardware.sensor.gyroscope" />
<uses-feature android:glEsVersion="0x00020000" />

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".App"
android:allowBackup="true"
android:enableOnBackInvokedCallback="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/Theme.App"
tools:targetApi="33">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_short_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.APPLICATION_PREFERENCES" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".CrashActivity"
android:label="Crash"
android:theme="@style/Theme.AppCompat.Light" />
</application>

</manifest>
57 changes: 57 additions & 0 deletions app/src/main/java/me/testcase/ognarviewer/App.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright © 2024 Ivan Akulinchev <ivan.akulinchev@gmail.com>
*
* This program 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.
*
* This program 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
* this program. If not, see <https://www.gnu.org/licenses/>.
*/

package me.testcase.ognarviewer;

import android.app.Application;
import android.os.StrictMode;

import me.testcase.ognarviewer.directory.DirectoryRepository;
import me.testcase.ognarviewer.directory.PrivateDirectory;
import me.testcase.ognarviewer.directory.PublicDirectory;

public class App extends Application {
private static DirectoryRepository sDirectoryRepository;

@Override
public void onCreate() {
super.onCreate();

if (BuildConfig.DEBUG) {
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder(StrictMode.getVmPolicy())
.detectAll()
.penaltyLog()
.build());
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build());
}

Thread.setDefaultUncaughtExceptionHandler(new GlobalExceptionHandler(this,
Thread.getDefaultUncaughtExceptionHandler()));

final PublicDirectory publicDirectory = new PublicDirectory(this);
final PrivateDirectory privateDirectory = new PrivateDirectory(this);
sDirectoryRepository = new DirectoryRepository(publicDirectory, privateDirectory);
}

// TODO: use dependency injection.
public static DirectoryRepository getDirectoryRepository() {
return sDirectoryRepository;
}
}
57 changes: 57 additions & 0 deletions app/src/main/java/me/testcase/ognarviewer/CalibratedClock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright © 2024 Ivan Akulinchev <ivan.akulinchev@gmail.com>
*
* This program 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.
*
* This program 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
* this program. If not, see <https://www.gnu.org/licenses/>.
*/

package me.testcase.ognarviewer;

import android.location.Location;

import androidx.annotation.MainThread;

/**
* An "exact" GPS-based clock, because the system time may be incorrect.
*/
public class CalibratedClock {
/**
* Time error.
*
* <p>If zero, the system time is in sync with the GPS time. If negative, the system time is
* ahead of the GPS time. If positive, the system time is behind the GPS time.</p>
*/
private static volatile long sTimeError;

/**
* Get the current time in milliseconds.
*
* <p>The time is believed to be "correct", even if an incorrect time is set in the system.</p>
*/
public static long currentTimeMillis() {
return System.currentTimeMillis() + sTimeError;
}

public static long getTimeError() {
return sTimeError;
}

@MainThread
public static void sync(Location location) {
sTimeError = location.getTime() - System.currentTimeMillis();
if (Math.abs(sTimeError) <= 50) {
// It's more likely a propagation delay than an incorrect system clock.
sTimeError = 0;
}
}
}
72 changes: 72 additions & 0 deletions app/src/main/java/me/testcase/ognarviewer/CrashActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright © 2024 Ivan Akulinchev <ivan.akulinchev@gmail.com>
*
* This program 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.
*
* This program 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
* this program. If not, see <https://www.gnu.org/licenses/>.
*/

package me.testcase.ognarviewer;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

public class CrashActivity extends AppCompatActivity {
private static final String TAG = "CrashActivity";

private final ActivityResultLauncher<Intent> mSendBacktrace = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), result -> finish());

private String mBacktrace;

@Override
public void onCreate(Bundle savedInstanceState) {
Log.v(TAG, String.format("CrashActivity %h created", this));
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crash);
final Intent intent = getIntent();
final Bundle extras = intent.getExtras();
if (extras != null) {
mBacktrace = extras.getString("backtrace");
final TextView textView = findViewById(R.id.backtrace);
textView.setText(mBacktrace);
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_crash, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.action_email) {
final Intent intent = new Intent(Intent.ACTION_SENDTO);
intent.setData(Uri.parse("mailto:ivan.akulinchev@gmail.com"));
intent.putExtra(Intent.EXTRA_SUBJECT, "OGN AR Viewer has crashed");
intent.putExtra(Intent.EXTRA_TEXT, mBacktrace);
mSendBacktrace.launch(intent);
return true;
}
return super.onOptionsItemSelected(item);
}
}
Loading

0 comments on commit 96a5827

Please sign in to comment.