Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
petrnalevka committed Aug 7, 2020
0 parents commit 2f3f9b9
Show file tree
Hide file tree
Showing 32 changed files with 693 additions and 0 deletions.
46 changes: 46 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 30

defaultConfig {
applicationId "com.urbandroid.recordforeground"
minSdkVersion 26
targetSdkVersion 30
versionCode 1
versionName "1.0"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

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'
}
}

dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.1'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment-ktx:2.3.0'
implementation 'androidx.navigation:navigation-ui-ktx:2.3.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'

}
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.urbandroid.recordforeground

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith

/**
* 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.getInstrumentation().targetContext
assertEquals("com.urbandroid.recordforeground", appContext.packageName)
}
}
35 changes: 35 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.urbandroid.recordforeground">

<uses-feature
android:name="android.hardware.microphone"
android:required="false"/>

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

<application
android:allowBackup="true"
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.MAIN" />

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

<service
android:foregroundServiceType="microphone"
android:name=".RecordingService"/>
</application>

</manifest>
61 changes: 61 additions & 0 deletions app/src/main/java/com/urbandroid/recordforeground/MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.urbandroid.recordforeground

import android.Manifest
import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
import java.util.concurrent.TimeUnit

const val TAG : String = "RecordForeground"

const val NOTIFICATION_CHANNEL_FOREGROUND = "foreground"

class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(findViewById(R.id.toolbar))

startLater.setOnClickListener {
val time = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10)
Log.i(TAG, "Scheduling start ${Date(time)}")
val am = getSystemService(Context.ALARM_SERVICE) as AlarmManager
am.setExactAndAllowWhileIdle(AlarmManager.RTC, time, PendingIntent.getForegroundService(this, 0, Intent(this, RecordingService::class.java), PendingIntent.FLAG_UPDATE_CURRENT))

Toast.makeText(this, "Foreground service will start in a minute", Toast.LENGTH_LONG).show()
finish()
}

startNow.setOnClickListener {
startForegroundService(Intent(this, RecordingService::class.java))
}

requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), 0)
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.menu_main, menu)
return true
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
return when (item.itemId) {
R.id.action_settings -> true
else -> super.onOptionsItemSelected(item)
}
}
}
107 changes: 107 additions & 0 deletions app/src/main/java/com/urbandroid/recordforeground/RecordingService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package com.urbandroid.recordforeground

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.media.AudioFormat
import android.media.AudioRecord
import android.media.MediaRecorder
import android.net.Uri
import android.os.Build
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat

class RecordingService : Service() {

override fun onBind(p0: Intent?): IBinder? {
return null
}

override fun onCreate() {
super.onCreate()

Log.i(TAG, "Foreground service created")

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

val channelName = "Foreground"
val importance = NotificationManager.IMPORTANCE_LOW
val notificationChannel = NotificationChannel(NOTIFICATION_CHANNEL_FOREGROUND, channelName, importance)
notificationChannel.setShowBadge(false)
notificationManager.createNotificationChannel(notificationChannel);
}

val i = Intent(this, MainActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
val pi = PendingIntent.getActivity(this, 4242, i, PendingIntent.FLAG_UPDATE_CURRENT)

val context = this

var intent = Intent()

if (Build.VERSION.SDK_INT >= 26) {
intent = Intent(android.provider.Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(android.provider.Settings.EXTRA_CHANNEL_ID, NOTIFICATION_CHANNEL_FOREGROUND)
intent.putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, context.packageName)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
} else if (Build.VERSION.SDK_INT >= 23) {
intent.setClassName("com.android.settings", "com.android.settings.Settings\$AppNotificationSettingsActivity")
intent.putExtra("app_package", context.packageName)
intent.putExtra("app_uid", context.applicationInfo.uid)

if (Build.VERSION.SDK_INT >= 26) {
intent.putExtra(android.provider.Settings.EXTRA_CHANNEL_ID, NOTIFICATION_CHANNEL_FOREGROUND)
}
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)

intent.putExtra("android.provider.extra.APP_PACKAGE", context.packageName)
} else if (Build.VERSION.SDK_INT > 16) {
try {
intent = Intent()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
intent.action = android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts("package", context.packageName, null)
intent.data = uri
} catch (e: Exception) {
Log.e(TAG, "Error", e)
}

}

val notificationBuilder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_FOREGROUND)
.setChannelId(NOTIFICATION_CHANNEL_FOREGROUND)
.setColor(ContextCompat.getColor(applicationContext, R.color.colorAccent))
.setContentIntent(pi)
.setShowWhen(false)
.setContentText("Running")

startForeground(2342, notificationBuilder.build())

Log.i(TAG, "Foreground service started")

val minBufferSize = AudioRecord.getMinBufferSize(44100, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT)

val recorder = AudioRecord(
MediaRecorder.AudioSource.MIC,
44100,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
minBufferSize)

if (recorder.state == AudioRecord.STATE_UNINITIALIZED) {
// this condition is true even this is called from a process with an active foreground service
Log.i(TAG, "Recorder uninitialized FAILED")
} else {
Log.i(TAG, "Recorder initialized SUCCESS")
}

recorder.release()
stopSelf()
}
}
30 changes: 30 additions & 0 deletions app/src/main/res/drawable-v24/ic_launcher_foreground.xml
Original file line number Diff line number Diff line change
@@ -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>
Loading

0 comments on commit 2f3f9b9

Please sign in to comment.