Browse Source

Init

master
Wouter Habets 2 years ago
commit
69d2597092
Signed by: Wouter Habets <wouterhabets@gmail.com> GPG Key ID: 0849A79A56BC6806
58 changed files with 1049 additions and 0 deletions
  1. 75
    0
      .gitignore
  2. 1
    0
      app/.gitignore
  3. 40
    0
      app/build.gradle
  4. 25
    0
      app/proguard-rules.pro
  5. 24
    0
      app/src/androidTest/java/io/habets/jellyfish/ExampleInstrumentedTest.kt
  6. 44
    0
      app/src/main/AndroidManifest.xml
  7. BIN
      app/src/main/ic_launcher-web.png
  8. 13
    0
      app/src/main/java/io/habets/jellyfish/App.kt
  9. 134
    0
      app/src/main/java/io/habets/jellyfish/AudioService.kt
  10. 4
    0
      app/src/main/java/io/habets/jellyfish/Events.kt
  11. 22
    0
      app/src/main/java/io/habets/jellyfish/Launcher.kt
  12. 68
    0
      app/src/main/java/io/habets/jellyfish/MainActivity.kt
  13. BIN
      app/src/main/res/drawable-hdpi/ic_shortcut_car.png
  14. BIN
      app/src/main/res/drawable-hdpi/ic_speaker.png
  15. BIN
      app/src/main/res/drawable-mdpi/ic_shortcut_car.png
  16. BIN
      app/src/main/res/drawable-mdpi/ic_speaker.png
  17. BIN
      app/src/main/res/drawable-xhdpi/ic_shortcut_car.png
  18. BIN
      app/src/main/res/drawable-xhdpi/ic_speaker.png
  19. BIN
      app/src/main/res/drawable-xxhdpi/ic_shortcut_car.png
  20. BIN
      app/src/main/res/drawable-xxhdpi/ic_speaker.png
  21. BIN
      app/src/main/res/drawable-xxxhdpi/ic_shortcut_car.png
  22. 113
    0
      app/src/main/res/drawable/ic_launcher_background.xml
  23. 9
    0
      app/src/main/res/layout/activity_launcher.xml
  24. 25
    0
      app/src/main/res/layout/activity_main.xml
  25. 52
    0
      app/src/main/res/layout/content_main.xml
  26. 10
    0
      app/src/main/res/menu/menu_main.xml
  27. 5
    0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  28. 5
    0
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  29. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher.png
  30. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
  31. BIN
      app/src/main/res/mipmap-hdpi/ic_launcher_round.png
  32. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher.png
  33. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
  34. BIN
      app/src/main/res/mipmap-mdpi/ic_launcher_round.png
  35. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher.png
  36. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
  37. BIN
      app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
  38. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher.png
  39. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
  40. BIN
      app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
  41. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
  42. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
  43. BIN
      app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
  44. 6
    0
      app/src/main/res/values/colors.xml
  45. 3
    0
      app/src/main/res/values/dimens.xml
  46. 4
    0
      app/src/main/res/values/ic_launcher_background.xml
  47. 5
    0
      app/src/main/res/values/strings.xml
  48. 24
    0
      app/src/main/res/values/styles.xml
  49. 4
    0
      app/src/main/res/xml/backup_descriptor.xml
  50. 15
    0
      app/src/main/res/xml/shortcuts.xml
  51. 17
    0
      app/src/test/java/io/habets/jellyfish/ExampleUnitTest.kt
  52. 28
    0
      build.gradle
  53. 17
    0
      gradle.properties
  54. BIN
      gradle/wrapper/gradle-wrapper.jar
  55. 6
    0
      gradle/wrapper/gradle-wrapper.properties
  56. 160
    0
      gradlew
  57. 90
    0
      gradlew.bat
  58. 1
    0
      settings.gradle

+ 75
- 0
.gitignore View File

@@ -0,0 +1,75 @@

# Created by https://www.gitignore.io/api/linux,android

### Android ###
# Built application files
*.apk
*.ap_

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# Intellij
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/dictionaries
.idea/libraries

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild

# Freeline
freeline.py
freeline/
freeline_project_description.json

### Android Patch ###
gen-external-apklibs

### Linux ###
*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*

# End of https://www.gitignore.io/api/linux,android

.idea/

+ 1
- 0
app/.gitignore View File

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

+ 40
- 0
app/build.gradle View File

@@ -0,0 +1,40 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "io.habets.jellyfish"
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:26.0.1'
testImplementation 'junit:junit:4.12'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:26.0.1'
implementation 'com.google.android.gms:play-services-location:11.0.4'
implementation 'com.jakewharton.timber:timber:4.5.1'
implementation 'org.greenrobot:eventbus:3.0.0'
implementation "android.arch.lifecycle:runtime:1.0.0-alpha8"
implementation "android.arch.lifecycle:extensions:1.0.0-alpha8"
annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha8"
}

+ 25
- 0
app/proguard-rules.pro View File

@@ -0,0 +1,25 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /opt/android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# 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

+ 24
- 0
app/src/androidTest/java/io/habets/jellyfish/ExampleInstrumentedTest.kt View File

@@ -0,0 +1,24 @@
package io.habets.jellyfish

import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4

import org.junit.Test
import org.junit.runner.RunWith

import org.junit.Assert.*

/**
* Instrumented test, which will execute on an Android device.
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
assertEquals("io.habets.jellyfish", appContext.packageName)
}
}

+ 44
- 0
app/src/main/AndroidManifest.xml View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.habets.jellyfish">

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

<application
android:name=".App"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_descriptor"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>

<service
android:name=".AudioService"
android:enabled="true"
android:exported="false" />

<activity
android:name=".Launcher"
android:theme="@style/AppTheme.Transparent" />
</application>

</manifest>

BIN
app/src/main/ic_launcher-web.png View File


+ 13
- 0
app/src/main/java/io/habets/jellyfish/App.kt View File

@@ -0,0 +1,13 @@
package io.habets.jellyfish

import android.app.Application
import timber.log.Timber

class App : Application() {
override fun onCreate() {
super.onCreate()
if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
}
}

+ 134
- 0
app/src/main/java/io/habets/jellyfish/AudioService.kt View File

@@ -0,0 +1,134 @@
package io.habets.jellyfish

import android.app.*
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.media.AudioManager
import android.os.IBinder
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import com.google.android.gms.location.*
import org.greenrobot.eventbus.EventBus
import timber.log.Timber

class AudioService : Service() {
private val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult?) {
super.onLocationResult(result)
if (result == null) return
val speed = (result.lastLocation.speed * 3.6).toInt()
val volume = when (speed) {
in 80..150 -> changeVolume(15)
in 60..80 -> changeVolume(14)
in 0..60 -> changeVolume(13)
else -> -1
}
EventBus.getDefault().post(LocationUpdateEvent(speed, System.currentTimeMillis(), volume, maxVolume))
}
}
private val carModeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == UiModeManager.ACTION_EXIT_CAR_MODE) {
stopSelf()
}
}
}
private val noisyReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
if (intent?.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY) {
stopSelf()
(getSystemService(Context.UI_MODE_SERVICE) as UiModeManager).disableCarMode(UiModeManager.DISABLE_CAR_MODE_GO_HOME)
}
}
}
private val fusedLocationClient: FusedLocationProviderClient by lazy {
LocationServices.getFusedLocationProviderClient(this)
}
private val audioManager: AudioManager by lazy {
getSystemService(Context.AUDIO_SERVICE) as AudioManager
}
private val maxVolume: Int by lazy {
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
}
private var previousVolume = -1

private fun changeVolume(value: Int): Int {
if (value == -1) return -1
val newVolume = map(value, 0, 15, 0, maxVolume)
if (previousVolume != newVolume) {
previousVolume = newVolume
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, newVolume, if (BuildConfig.DEBUG) AudioManager.FLAG_SHOW_UI else 0)
}
return previousVolume
}

private fun map(x: Int, inMin: Int, inMax: Int, outMin: Int, outMax: Int): Int =
((x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin)


override fun onBind(intent: Intent): IBinder? = null

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
return super.onStartCommand(intent, flags, startId)
}

override fun onCreate() {
super.onCreate()
createNotificationChannel(this)
startForeground(ID, createNotification(this))
startUpdates()
registerReceiver(carModeReceiver, IntentFilter(UiModeManager.ACTION_EXIT_CAR_MODE))
registerReceiver(noisyReceiver, IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY))
}

override fun onDestroy() {
super.onDestroy()
stopUpdates()
unregisterReceiver(carModeReceiver)
unregisterReceiver(noisyReceiver)
}

private fun startUpdates() {
val request = LocationRequest()
.setInterval(5000)
.setFastestInterval(1000)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
fusedLocationClient.requestLocationUpdates(request, callback, null)
Timber.d("Starting location updates")
EventBus.getDefault().post(LocationStateEvent(true))
}

private fun stopUpdates() {
fusedLocationClient.removeLocationUpdates(callback)
Timber.d("Stopping location updates")
EventBus.getDefault().post(LocationStateEvent(false))
}

companion object {
const val ID = 101
const val NOTIFICATION_CHANNEL = "service"
fun createNotificationChannel(context: Context) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.O) return
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val name = "Service notification"
val description = "Display notification while the service is running."
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(NOTIFICATION_CHANNEL, name, importance)
channel.description = description
channel.enableLights(false)
channel.enableVibration(false)
notificationManager.createNotificationChannel(channel)
}

fun createNotification(context: Context): Notification =
NotificationCompat.Builder(context, NOTIFICATION_CHANNEL)
.setContentTitle(context.getString(R.string.app_name))
.setContentText("Service running")
.setSmallIcon(R.drawable.ic_speaker)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.build()
}
}

+ 4
- 0
app/src/main/java/io/habets/jellyfish/Events.kt View File

@@ -0,0 +1,4 @@
package io.habets.jellyfish

data class LocationUpdateEvent(val speed: Int, val time: Long, val volume: Int, val maxVolume: Int)
data class LocationStateEvent(val enabled: Boolean)

+ 22
- 0
app/src/main/java/io/habets/jellyfish/Launcher.kt View File

@@ -0,0 +1,22 @@
package io.habets.jellyfish

import android.app.Activity
import android.app.UiModeManager
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle

class Launcher : Activity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(Intent(this, AudioService::class.java))
} else {
startService(Intent(this, AudioService::class.java))
}
(getSystemService(Context.UI_MODE_SERVICE) as UiModeManager).enableCarMode(UiModeManager.ENABLE_CAR_MODE_GO_CAR_HOME)
finish()
}
}

+ 68
- 0
app/src/main/java/io/habets/jellyfish/MainActivity.kt View File

@@ -0,0 +1,68 @@
package io.habets.jellyfish

import android.arch.lifecycle.LifecycleRegistry
import android.arch.lifecycle.LifecycleRegistryOwner
import android.content.Intent
import android.media.AudioManager
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.Menu
import android.view.MenuItem
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.content_main.*
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode

class MainActivity : AppCompatActivity(), LifecycleRegistryOwner {

private val lifecycleRegistry = LifecycleRegistry(this)
override fun getLifecycle(): LifecycleRegistry = lifecycleRegistry

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
buttonEnable.setOnClickListener {
startService(Intent(this, AudioService::class.java))
}
buttonDisable.setOnClickListener { stopService(Intent(this, AudioService::class.java)) }
volumeControlStream = AudioManager.STREAM_MUSIC
}

override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}

override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}

@Subscribe(threadMode = ThreadMode.MAIN)
fun onLocationUpdate(event: LocationUpdateEvent) {
textView.text = "Speed: ${event.speed} km/h\nTime: ${event.time}\nVolume: ${event.volume}\nVol max: ${event.maxVolume}"
}

@Subscribe(threadMode = ThreadMode.MAIN)
fun onLocationStateEvent(event: LocationStateEvent) {
if (event.enabled) {
textView.text = "Service started"
} else {
textView.text = "Service stopped"
}
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
}

BIN
app/src/main/res/drawable-hdpi/ic_shortcut_car.png View File


BIN
app/src/main/res/drawable-hdpi/ic_speaker.png View File


BIN
app/src/main/res/drawable-mdpi/ic_shortcut_car.png View File


BIN
app/src/main/res/drawable-mdpi/ic_speaker.png View File


BIN
app/src/main/res/drawable-xhdpi/ic_shortcut_car.png View File


BIN
app/src/main/res/drawable-xhdpi/ic_speaker.png View File


BIN
app/src/main/res/drawable-xxhdpi/ic_shortcut_car.png View File


BIN
app/src/main/res/drawable-xxhdpi/ic_speaker.png View File


BIN
app/src/main/res/drawable-xxxhdpi/ic_shortcut_car.png View File


+ 113
- 0
app/src/main/res/drawable/ic_launcher_background.xml View File

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


+ 9
- 0
app/src/main/res/layout/activity_launcher.xml View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.habets.jellyfish.Launcher">

</android.support.constraint.ConstraintLayout>

+ 25
- 0
app/src/main/res/layout/activity_main.xml View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="io.habets.jellyfish.MainActivity">

<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay" />

</android.support.design.widget.AppBarLayout>

<include layout="@layout/content_main" />

</android.support.design.widget.CoordinatorLayout>

+ 52
- 0
app/src/main/res/layout/content_main.xml View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="io.habets.jellyfish.MainActivity"
tools:showIn="@layout/activity_main"
tools:layout_editor_absoluteY="81dp"
tools:layout_editor_absoluteX="0dp">

<Button
android:id="@+id/buttonEnable"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:text="Enable"
tools:layout_editor_absoluteX="16dp"
tools:layout_editor_absoluteY="19dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toStartOf="@+id/buttonDisable"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp" />

<Button
android:id="@+id/buttonDisable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Disable"
tools:layout_editor_absoluteX="280dp"
tools:layout_editor_absoluteY="16dp"
app:layout_constraintStart_toEndOf="@+id/buttonEnable"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="16dp" />

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="No updates"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:layout_editor_absoluteX="162dp"
tools:layout_editor_absoluteY="245dp" />
</android.support.constraint.ConstraintLayout>

+ 10
- 0
app/src/main/res/menu/menu_main.xml View File

@@ -0,0 +1,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="io.habets.jellyfish.MainActivity">
<item
android:id="@+id/action_settings"
android:orderInCategory="100"
android:title="@string/action_settings"
app:showAsAction="never" />
</menu>

+ 5
- 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml View File

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

+ 5
- 0
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml View File

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

BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png View File


BIN
app/src/main/res/mipmap-hdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png View File


BIN
app/src/main/res/mipmap-mdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png View File


BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png View File


BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png View File


BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png View File


+ 6
- 0
app/src/main/res/values/colors.xml View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

+ 3
- 0
app/src/main/res/values/dimens.xml View File

@@ -0,0 +1,3 @@
<resources>
<dimen name="fab_margin">16dp</dimen>
</resources>

+ 4
- 0
app/src/main/res/values/ic_launcher_background.xml View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#3F51B5</color>
</resources>

+ 5
- 0
app/src/main/res/values/strings.xml View File

@@ -0,0 +1,5 @@
<resources>
<string name="app_name">Jellyfish</string>
<string name="action_settings">Settings</string>
<string name="shortcut_launch">Car mode</string>
</resources>

+ 24
- 0
app/src/main/res/values/styles.xml View File

@@ -0,0 +1,24 @@
<resources>

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>

<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.Transparent">
<item name="android:windowBackground">@android:color/transparent</item>
</style>

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />

<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

</resources>

+ 4
- 0
app/src/main/res/xml/backup_descriptor.xml View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<full-backup-content>
<!-- Exclude specific shared preferences that contain GCM registration Id -->
</full-backup-content>

+ 15
- 0
app/src/main/res/xml/shortcuts.xml View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<shortcut
android:enabled="true"
android:icon="@drawable/ic_shortcut_car"
android:shortcutId="launcher"
android:shortcutShortLabel="@string/shortcut_launch"
tools:ignore="UnusedAttribute">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="io.habets.jellyfish.Launcher"
android:targetPackage="io.habets.jellyfish" />
</shortcut>
</shortcuts>

+ 17
- 0
app/src/test/java/io/habets/jellyfish/ExampleUnitTest.kt View File

@@ -0,0 +1,17 @@
package io.habets.jellyfish

import org.junit.Test

import org.junit.Assert.*

/**
* Example local unit test, which will execute on the development machine (host).
*
* See [testing documentation](http://d.android.com/tools/testing).
*/
class ExampleUnitTest {
@Test
fun addition_isCorrect() {
assertEquals(4, 2 + 2)
}
}

+ 28
- 0
build.gradle View File

@@ -0,0 +1,28 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.1.3-2'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-beta2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}

allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}

task clean(type: Delete) {
delete rootProject.buildDir
}

+ 17
- 0
gradle.properties View File

@@ -0,0 +1,17 @@
# 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=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar View File


+ 6
- 0
gradle/wrapper/gradle-wrapper.properties View File

@@ -0,0 +1,6 @@
#Sun Aug 06 21:42:40 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-rc-1-all.zip

+ 160
- 0
gradlew View File

@@ -0,0 +1,160 @@
#!/usr/bin/env bash

##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# 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
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac

# 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

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" ] ; 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, switch paths to Windows format before running java
if $cygwin ; 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=$((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

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

+ 90
- 0
gradlew.bat View File

@@ -0,0 +1,90 @@
@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

@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=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@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 init

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 init

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

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

: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 %CMD_LINE_ARGS%

: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

+ 1
- 0
settings.gradle View File

@@ -0,0 +1 @@
include ':app'

Loading…
Cancel
Save