Skip to content

Commit

Permalink
Omni: Update to 1.2
Browse files Browse the repository at this point in the history
Signed-off-by: AkaneTan <dev@akane.uk>
  • Loading branch information
AkaneTan committed Oct 6, 2024
1 parent c8bd198 commit bea7f78
Show file tree
Hide file tree
Showing 65 changed files with 2,599 additions and 196 deletions.
1 change: 0 additions & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ android {
applicationId = "uk.akane.omni"
minSdk = 26
targetSdk = 34
versionCode = 2
versionName = "1.1"
versionCode = 3
versionName = "1.2"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
24 changes: 5 additions & 19 deletions app/src/main/java/uk/akane/omni/logic/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import android.content.res.Configuration
import android.graphics.Color
import android.hardware.SensorManager
import androidx.core.graphics.Insets
import android.os.Looper
import android.os.StrictMode
import android.view.View
import android.widget.TextView
import androidx.activity.ComponentActivity
Expand All @@ -20,7 +18,6 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.children
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.appbar.CollapsingToolbarLayout
import uk.akane.omni.BuildConfig

@Suppress("NOTHING_TO_INLINE")
inline fun Context.doIHavePermission(perm: String) =
Expand Down Expand Up @@ -106,21 +103,6 @@ fun SensorManager.checkSensorAvailability(sensorType: Int): Boolean {
return getDefaultSensor(sensorType) != null
}

// the whole point of this function is to do literally nothing at all (but without impacting
// performance) in release builds and ignore StrictMode violations in debug builds
inline fun <reified T> allowDiskAccessInStrictMode(doIt: () -> T): T {
return if (BuildConfig.DEBUG) {
if (Looper.getMainLooper() != Looper.myLooper()) throw IllegalStateException()
val policy = StrictMode.allowThreadDiskReads()
try {
StrictMode.allowThreadDiskWrites()
doIt()
} finally {
StrictMode.setThreadPolicy(policy)
}
} else doIt()
}

fun View.enableEdgeToEdgePaddingListener(ime: Boolean = false, top: Boolean = false,
extra: ((Insets) -> Unit)? = null) {
if (fitsSystemWindows) throw IllegalArgumentException("must have fitsSystemWindows disabled")
Expand Down Expand Up @@ -186,4 +168,8 @@ fun View.enableEdgeToEdgePaddingListener(ime: Boolean = false, top: Boolean = fa

@Suppress("NOTHING_TO_INLINE")
inline fun Int.dpToPx(context: Context): Int =
(this.toFloat() * context.resources.displayMetrics.density).toInt()
(this.toFloat() * context.resources.displayMetrics.density).toInt()

@Suppress("NOTHING_TO_INLINE")
inline fun Float.dpToPx(context: Context): Float =
(this * context.resources.displayMetrics.density)
150 changes: 150 additions & 0 deletions app/src/main/java/uk/akane/omni/logic/services/CompassTileService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
package uk.akane.omni.logic.services

import android.annotation.SuppressLint
import android.app.NotificationChannel
import android.app.NotificationManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService
import android.util.Log
import android.view.Surface
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import uk.akane.omni.R
import kotlin.math.absoluteValue

class CompassTileService : TileService(), SensorEventListener {

private val sensorManager
get() = getSystemService<SensorManager>()
private val rotationVectorSensor
get() = sensorManager?.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
private val notificationManager
get() = getSystemService<NotificationManager>()
private lateinit var rotationIcon: Drawable
private lateinit var iconBitmap: Bitmap


companion object {
const val CHANNEL_ID = "COMPASS_CHANNEL"
const val NOTIFICATION_ID = 1
}

override fun onCreate() {
super.onCreate()
notificationManager?.createNotificationChannel(
NotificationChannel(
CHANNEL_ID,
getString(R.string.compass_tile_notification_channel),
NotificationManager.IMPORTANCE_LOW
)
)
rotationIcon = AppCompatResources.getDrawable(this, R.drawable.ic_pointer)!!
iconBitmap = Bitmap.createBitmap(
rotationIcon.intrinsicWidth, rotationIcon.intrinsicHeight,
Bitmap.Config.ARGB_8888
)
}

override fun onClick() {
super.onClick()
Log.d("TAG", "onClick")
qsTile.state = when (qsTile.state) {
Tile.STATE_ACTIVE -> Tile.STATE_INACTIVE
Tile.STATE_INACTIVE -> Tile.STATE_ACTIVE
else -> Tile.STATE_INACTIVE
}
if (qsTile.state == Tile.STATE_INACTIVE) {
qsTile.label = getString(R.string.compass)
}
qsTile.updateTile()
}

override fun onStartListening() {
super.onStartListening()
Log.d("TAG", "START LISTENING")
if (qsTile.state == Tile.STATE_ACTIVE) {
startForeground(
NOTIFICATION_ID,
NotificationCompat.Builder(this, CHANNEL_ID).setSmallIcon(R.drawable.ic_explorer)
.setContentTitle(getString(R.string.compass_notification_title))
.setContentText(getString(R.string.compass_notification_label))
.build()
)
sensorManager?.registerListener(
this,
rotationVectorSensor,
SensorManager.SENSOR_DELAY_FASTEST
)
}
}

override fun onStopListening() {
super.onStopListening()
if (qsTile.state == Tile.STATE_ACTIVE) {
sensorManager?.unregisterListener(this)
stopForeground(STOP_FOREGROUND_REMOVE)
}
Log.d("TAG", "STOP LISTENING")
}

override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_ROTATION_VECTOR && qsTile.state == Tile.STATE_ACTIVE) {
updateCompass(event)
}
}

@SuppressLint("StringFormatMatches")
private fun updateCompass(event: SensorEvent) {
val rotationVector = event.values.take(3).toFloatArray()
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrixFromVector(rotationMatrix, rotationVector)

val displayRotation = ContextCompat.getDisplayOrDefault(baseContext).rotation
val remappedRotationMatrix = remapRotationMatrix(rotationMatrix, displayRotation)

val orientationInRadians = FloatArray(3)
SensorManager.getOrientation(remappedRotationMatrix, orientationInRadians)

val azimuthInDegrees = Math.toDegrees(orientationInRadians[0].toDouble()).toFloat()
val adjustedAzimuth = (azimuthInDegrees + 360) % 360

Canvas(iconBitmap).apply {
drawColor(Color.BLACK, PorterDuff.Mode.CLEAR) // clear all
rotate(-adjustedAzimuth, width / 2f, height / 2f)
rotationIcon.setBounds(0, 0, width, height)
rotationIcon.draw(this)
}

qsTile.label = getString(R.string.degree_format_tile, adjustedAzimuth.toInt().absoluteValue)
qsTile.icon = Icon.createWithBitmap(iconBitmap)

qsTile.updateTile()
}

private fun remapRotationMatrix(rotationMatrix: FloatArray, displayRotation: Int): FloatArray {
val (newX, newY) = when (displayRotation) {
Surface.ROTATION_90 -> Pair(SensorManager.AXIS_Y, SensorManager.AXIS_MINUS_X)
Surface.ROTATION_180 -> Pair(SensorManager.AXIS_MINUS_X, SensorManager.AXIS_MINUS_Y)
Surface.ROTATION_270 -> Pair(SensorManager.AXIS_MINUS_Y, SensorManager.AXIS_X)
else -> Pair(SensorManager.AXIS_X, SensorManager.AXIS_Y)
}

val remappedRotationMatrix = FloatArray(9)
SensorManager.remapCoordinateSystem(rotationMatrix, newX, newY, remappedRotationMatrix)
return remappedRotationMatrix
}

override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) = Unit
}
26 changes: 26 additions & 0 deletions app/src/main/java/uk/akane/omni/ui/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
package uk.akane.omni.ui

import android.os.Bundle
import android.util.Log
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import uk.akane.omni.R
import uk.akane.omni.logic.enableEdgeToEdgeProperly
import uk.akane.omni.ui.fragments.FlashlightFragment
import uk.akane.omni.ui.fragments.LevelFragment
import uk.akane.omni.ui.fragments.RulerFragment

class MainActivity : AppCompatActivity() {

Expand All @@ -17,6 +22,27 @@ class MainActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
enableEdgeToEdgeProperly()
setContentView(R.layout.activity_main)
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

Log.d("TAG", "YES:: ${intent.extras}")
if (intent.hasExtra("targetFragment")) {
intent.getIntExtra("targetFragment", 0).let {
when (it) {
1 -> {
startFragment(LevelFragment())
postComplete()
}
2 -> {
startFragment(RulerFragment())
postComplete()
}
3 -> {
startFragment(FlashlightFragment())
postComplete()
}
}
}
}
}

fun postComplete() = run { ready = true }
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/java/uk/akane/omni/ui/components/CompassView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ class CompassView @JvmOverloads constructor(

init {
inflate(context, R.layout.compass_layout, this)
degreeIndicatorTextView = findViewById(R.id.degree_indicator)
degreeIndicatorTextView = findViewById(R.id.degree_indicator)!!
directionTextViews = listOf(
findViewById(R.id.north), findViewById(R.id.east), findViewById(R.id.south), findViewById(R.id.west),
findViewById(R.id.direction_1), findViewById(R.id.direction_2), findViewById(R.id.direction_3),
findViewById(R.id.direction_4), findViewById(R.id.direction_5), findViewById(R.id.direction_6),
findViewById(R.id.direction_7), findViewById(R.id.direction_8), findViewById(R.id.direction_9),
findViewById(R.id.direction_10), findViewById(R.id.direction_11), findViewById(R.id.direction_12),
findViewById(R.id.north)!!, findViewById(R.id.east)!!, findViewById(R.id.south)!!, findViewById(R.id.west)!!,
findViewById(R.id.direction_1)!!, findViewById(R.id.direction_2)!!, findViewById(R.id.direction_3)!!,
findViewById(R.id.direction_4)!!, findViewById(R.id.direction_5)!!, findViewById(R.id.direction_6)!!,
findViewById(R.id.direction_7)!!, findViewById(R.id.direction_8)!!, findViewById(R.id.direction_9)!!,
findViewById(R.id.direction_10)!!, findViewById(R.id.direction_11)!!, findViewById(R.id.direction_12)!!,
degreeIndicatorTextView
)
}
Expand Down
85 changes: 85 additions & 0 deletions app/src/main/java/uk/akane/omni/ui/components/RulerView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package uk.akane.omni.ui.components

import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import uk.akane.omni.logic.dpToPx
import com.google.android.material.color.MaterialColors
import uk.akane.omni.R

class RulerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

private val paintText = Paint().apply {
color = MaterialColors.getColor(this@RulerView, com.google.android.material.R.attr.colorOutline)
strokeWidth = 2f.dpToPx(context)
textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20f, resources.displayMetrics)
typeface = resources.getFont(R.font.hgm)
isAntiAlias = true
}

private val paintMain = Paint().apply {
color = MaterialColors.getColor(this@RulerView, com.google.android.material.R.attr.colorOutline)
strokeWidth = 2f.dpToPx(context)
isAntiAlias = true
}

private val paintSide = Paint().apply {
color = MaterialColors.getColor(this@RulerView, com.google.android.material.R.attr.colorOutline)
alpha = 127
strokeWidth = 2f.dpToPx(context)
isAntiAlias = true
}

// Calculate 1mm in pixels
private val mmToPx: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1f, resources.displayMetrics)
private val topPadding: Float = 24f.dpToPx(context)

override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)

val width = width.toFloat()
val height = height.toFloat()

val numDivisions = ((height - topPadding) / mmToPx).toInt()
val longLineLength = width * 0.53f
val midLineLength = width * 0.43f
val shortLineLength = width * 0.34f

for (i in 0..numDivisions) {
val y = topPadding + i * mmToPx
when {
i % 10 == 0 -> {
// Draw longer lines and numbers for every 10mm (1cm)
canvas.drawLine(width - longLineLength, y, width, y, paintMain)
val text = (i / 10).toString()
val textWidth = paintText.measureText(text)
val textHeight = paintText.descent() - paintText.ascent()
val textX = (width - longLineLength) / 2 - textWidth / 2
val textY = y + textHeight / 3
paintText.color = MaterialColors.getColor(this@RulerView,
if ((i / 10) % 5 == 0)
com.google.android.material.R.attr.colorOnSurface
else
com.google.android.material.R.attr.colorOutline
)
canvas.drawText(text, textX, textY, paintText)
}
i % 5 == 0 -> {
// Draw medium lines for every 5mm (0.5cm)
canvas.drawLine(width - midLineLength, y, width, y, paintSide)
}
else -> {
// Draw shorter lines for other millimeters
canvas.drawLine(width - shortLineLength, y, width, y, paintSide)
}
}
}
}
}
Loading

0 comments on commit bea7f78

Please sign in to comment.