* working first release
This commit is contained in:
parent
6268d85d55
commit
7d60afaac4
109
.idea/codeStyles/Project.xml
generated
109
.idea/codeStyles/Project.xml
generated
@ -3,6 +3,115 @@
|
||||
<JetCodeStyleSettings>
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</JetCodeStyleSettings>
|
||||
<codeStyleSettings language="XML">
|
||||
<arrangement>
|
||||
<rules>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:android</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>xmlns:.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:id</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*:name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>name</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>style</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>ANDROID_ATTRIBUTE_ORDER</order>
|
||||
</rule>
|
||||
</section>
|
||||
<section>
|
||||
<rule>
|
||||
<match>
|
||||
<AND>
|
||||
<NAME>.*</NAME>
|
||||
<XML_ATTRIBUTE />
|
||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||
</AND>
|
||||
</match>
|
||||
<order>BY_NAME</order>
|
||||
</rule>
|
||||
</section>
|
||||
</rules>
|
||||
</arrangement>
|
||||
</codeStyleSettings>
|
||||
<codeStyleSettings language="kotlin">
|
||||
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||
</codeStyleSettings>
|
||||
|
||||
15
.idea/compiler.xml
generated
Normal file
15
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<wildcardResourcePatterns>
|
||||
<entry name="!?*.java" />
|
||||
<entry name="!?*.form" />
|
||||
<entry name="!?*.class" />
|
||||
<entry name="!?*.groovy" />
|
||||
<entry name="!?*.scala" />
|
||||
<entry name="!?*.flex" />
|
||||
<entry name="!?*.kt" />
|
||||
<entry name="!?*.clj" />
|
||||
</wildcardResourcePatterns>
|
||||
</component>
|
||||
</project>
|
||||
4
.idea/encodings.xml
generated
4
.idea/encodings.xml
generated
@ -1,4 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM" />
|
||||
<component name="Encoding" addBOMForNewFiles="with NO BOM">
|
||||
<file url="PROJECT" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8 (3)" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@ -16,6 +16,14 @@ android {
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
javaCompileOptions {
|
||||
annotationProcessorOptions {
|
||||
arguments = [
|
||||
"room.schemaLocation" : "$projectDir/schemas".toString(),
|
||||
"room.incremental" : "true",
|
||||
"room.expandProjection": "true"]
|
||||
}
|
||||
}
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
@ -31,17 +39,24 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'androidx.appcompat:appcompat:1.0.2'
|
||||
implementation 'androidx.core:core-ktx:1.0.2'
|
||||
implementation 'com.google.android.material:material:1.0.0'
|
||||
implementation 'androidx.preference:preference:1.1.0-rc01'
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.0.0'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test:runner:1.2.0'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
implementation 'khttp:khttp:0.1.0'
|
||||
implementation 'org.greenrobot:eventbus:3.1.1'
|
||||
|
||||
// implementation 'khttp:khttp:0.1.0'
|
||||
implementation 'io.karn:khttp-android:0.1.2'
|
||||
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
|
||||
// optional - Kotlin Extensions and Coroutines support for Room
|
||||
//implementation "androidx.room:room-ktx:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
|
||||
// optional - RxJava support for Room
|
||||
///implementation "androidx.room:room-rxjava2:$room_version"
|
||||
|
||||
58
app/schemas/hu.yvan.smsproxy.db.AppDatabase/1.json
Normal file
58
app/schemas/hu.yvan.smsproxy.db.AppDatabase/1.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "3c41cc5248bccd081b1049c7971f1456",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "pending_sms",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `contact` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `direction` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "contact",
|
||||
"columnName": "contact",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "message",
|
||||
"columnName": "message",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timestamp",
|
||||
"columnName": "timestamp",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "direction",
|
||||
"columnName": "direction",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3c41cc5248bccd081b1049c7971f1456')"
|
||||
]
|
||||
}
|
||||
}
|
||||
58
app/schemas/hu.yvan.smsproxy.db.AppDatabase/2.json
Normal file
58
app/schemas/hu.yvan.smsproxy.db.AppDatabase/2.json
Normal file
@ -0,0 +1,58 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 2,
|
||||
"identityHash": "3c41cc5248bccd081b1049c7971f1456",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "pending_sms",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `contact` TEXT NOT NULL, `message` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `direction` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "contact",
|
||||
"columnName": "contact",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "message",
|
||||
"columnName": "message",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "timestamp",
|
||||
"columnName": "timestamp",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "direction",
|
||||
"columnName": "direction",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"autoGenerate": true
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3c41cc5248bccd081b1049c7971f1456')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,6 @@
|
||||
package="hu.yvan.smsproxy">
|
||||
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.READ_SMS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
|
||||
@ -14,6 +13,26 @@
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme">
|
||||
|
||||
<activity
|
||||
android:name=".activity.SettingsActivity"
|
||||
android:label="@string/title_activity_settings"
|
||||
android:parentActivityName=".activity.MainActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="hu.yvan.smsproxy.activity.MainActivity"/>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activity.MainActivity"
|
||||
android:label="@string/title_activity_main"
|
||||
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:name=".service.SMSManager"
|
||||
android:exported="false">
|
||||
@ -24,7 +43,7 @@
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
</application>
|
||||
|
||||
107
app/src/main/java/hu/yvan/smsproxy/SmsFragment.kt
Normal file
107
app/src/main/java/hu/yvan/smsproxy/SmsFragment.kt
Normal file
@ -0,0 +1,107 @@
|
||||
package hu.yvan.smsproxy
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.room.Room
|
||||
import hu.yvan.smsproxy.db.AppDatabase
|
||||
import hu.yvan.smsproxy.db.SMS
|
||||
|
||||
/**
|
||||
* A fragment representing a list of Items.
|
||||
* Activities containing this fragment MUST implement the
|
||||
* [SmsFragment.OnListFragmentInteractionListener] interface.
|
||||
*/
|
||||
class SmsFragment : Fragment() {
|
||||
|
||||
// TODO: Customize parameters
|
||||
private var columnCount = 1
|
||||
|
||||
private var listener: OnListFragmentInteractionListener? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
arguments?.let {
|
||||
columnCount = it.getInt(ARG_COLUMN_COUNT)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
val view = inflater.inflate(R.layout.fragment_sms_list, container, false)
|
||||
|
||||
// Set the adapter
|
||||
if (view is RecyclerView) {
|
||||
with(view) {
|
||||
layoutManager = when {
|
||||
columnCount <= 1 -> LinearLayoutManager(context)
|
||||
else -> GridLayoutManager(context, columnCount)
|
||||
}
|
||||
val db = Room.databaseBuilder(context, AppDatabase::class.java, "sms_storage")
|
||||
.allowMainThreadQueries()
|
||||
.fallbackToDestructiveMigration()
|
||||
.build()
|
||||
val smses = db.smsDao().getAll().toMutableList()
|
||||
Log.d(SmsFragment::class.java.simpleName, db.smsDao().getAll().count().toString())
|
||||
|
||||
adapter = SmsRecyclerViewAdapter(smses, listener)
|
||||
}
|
||||
}
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
if (context is OnListFragmentInteractionListener) {
|
||||
listener = context
|
||||
} else {
|
||||
throw RuntimeException(context.toString() + " must implement OnListFragmentInteractionListener")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
super.onDetach()
|
||||
listener = null
|
||||
}
|
||||
|
||||
/**
|
||||
* This interface must be implemented by activities that contain this
|
||||
* fragment to allow an interaction in this fragment to be communicated
|
||||
* to the activity and potentially other fragments contained in that
|
||||
* activity.
|
||||
*
|
||||
*
|
||||
* See the Android Training lesson
|
||||
* [Communicating with Other Fragments](http://developer.android.com/training/basics/fragments/communicating.html)
|
||||
* for more information.
|
||||
*/
|
||||
interface OnListFragmentInteractionListener {
|
||||
// TODO: Update argument type and name
|
||||
fun onListFragmentInteraction(sms: SMS?, adapter: SmsRecyclerViewAdapter)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
// TODO: Customize parameter argument names
|
||||
const val ARG_COLUMN_COUNT = "column-count"
|
||||
|
||||
// TODO: Customize parameter initialization
|
||||
@JvmStatic
|
||||
fun newInstance(columnCount: Int) =
|
||||
SmsFragment().apply {
|
||||
arguments = Bundle().apply {
|
||||
putInt(ARG_COLUMN_COUNT, columnCount)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
app/src/main/java/hu/yvan/smsproxy/SmsPersistedEvent.kt
Normal file
3
app/src/main/java/hu/yvan/smsproxy/SmsPersistedEvent.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package hu.yvan.smsproxy
|
||||
|
||||
class SmsPersistedEvent(public val smsId: Long) {}
|
||||
67
app/src/main/java/hu/yvan/smsproxy/SmsRecyclerViewAdapter.kt
Normal file
67
app/src/main/java/hu/yvan/smsproxy/SmsRecyclerViewAdapter.kt
Normal file
@ -0,0 +1,67 @@
|
||||
package hu.yvan.smsproxy
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
|
||||
|
||||
import hu.yvan.smsproxy.SmsFragment.OnListFragmentInteractionListener
|
||||
import hu.yvan.smsproxy.db.SMS
|
||||
|
||||
import kotlinx.android.synthetic.main.fragment_sms.view.*
|
||||
|
||||
/**
|
||||
* [RecyclerView.Adapter] that can display a [SMS] and makes a call to the
|
||||
* specified [OnListFragmentInteractionListener].
|
||||
* TODO: Replace the implementation with code for your data type.
|
||||
*/
|
||||
class SmsRecyclerViewAdapter(
|
||||
private val mValues: MutableList<SMS>,
|
||||
private val mListener: OnListFragmentInteractionListener?
|
||||
) : RecyclerView.Adapter<SmsRecyclerViewAdapter.ViewHolder>() {
|
||||
|
||||
private val mOnClickListener: View.OnClickListener
|
||||
|
||||
init {
|
||||
mOnClickListener = View.OnClickListener { v ->
|
||||
val item = v.tag as SMS
|
||||
// Notify the active callbacks interface (the activity, if the fragment is attached to
|
||||
// one) that an item has been selected.
|
||||
mListener?.onListFragmentInteraction(item, this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context)
|
||||
.inflate(R.layout.fragment_sms, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val item = mValues[position]
|
||||
holder.mIdView.text = item.id.toString()
|
||||
holder.mContentView.text = item.message
|
||||
|
||||
with(holder.mView) {
|
||||
tag = item
|
||||
setOnClickListener(mOnClickListener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int = mValues.size
|
||||
|
||||
inner class ViewHolder(val mView: View) : RecyclerView.ViewHolder(mView) {
|
||||
val mIdView: TextView = mView.item_number
|
||||
val mContentView: TextView = mView.content
|
||||
|
||||
override fun toString(): String {
|
||||
return super.toString() + " '" + mContentView.text + "'"
|
||||
}
|
||||
}
|
||||
|
||||
fun removeItem(sms: SMS) {
|
||||
mValues.remove(sms)
|
||||
}
|
||||
}
|
||||
81
app/src/main/java/hu/yvan/smsproxy/activity/MainActivity.kt
Normal file
81
app/src/main/java/hu/yvan/smsproxy/activity/MainActivity.kt
Normal file
@ -0,0 +1,81 @@
|
||||
package hu.yvan.smsproxy.activity
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.room.Room
|
||||
import hu.yvan.smsproxy.SmsRecyclerViewAdapter
|
||||
import hu.yvan.smsproxy.R
|
||||
import hu.yvan.smsproxy.SmsFragment
|
||||
import hu.yvan.smsproxy.SmsPersistedEvent
|
||||
import hu.yvan.smsproxy.db.AppDatabase
|
||||
import hu.yvan.smsproxy.db.SMS
|
||||
import hu.yvan.smsproxy.service.SMSManager
|
||||
import kotlinx.android.synthetic.main.activity_main.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
|
||||
class MainActivity : AppCompatActivity(), SmsFragment.OnListFragmentInteractionListener {
|
||||
|
||||
lateinit var savedAdapter: SmsRecyclerViewAdapter
|
||||
|
||||
override fun onListFragmentInteraction(sms: SMS?, adapter: SmsRecyclerViewAdapter) {
|
||||
savedAdapter = adapter
|
||||
Log.d(TAG, "interact: $sms")
|
||||
if (sms != null) {
|
||||
SMSManager.startActionSMSResend(this, sms)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
setSupportActionBar(toolbar)
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_SMS) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(this,
|
||||
arrayOf(Manifest.permission.RECEIVE_SMS),
|
||||
MY_PERMISSIONS_REQUEST_READ_CONTACTS)
|
||||
}
|
||||
fab.setOnClickListener { view ->
|
||||
startActivity(Intent(this, SettingsActivity::class.java))
|
||||
}
|
||||
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
Log.d(TAG, "preferences: ${prefs.all}")
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
//Subscribe, run it on UI
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onEvent(event: SmsPersistedEvent) {
|
||||
val db = Room.databaseBuilder(this, AppDatabase::class.java, "sms_storage")
|
||||
.allowMainThreadQueries()
|
||||
.build()
|
||||
.smsDao()
|
||||
val sms = db.findById(event.smsId)
|
||||
savedAdapter.removeItem(sms)
|
||||
savedAdapter.notifyDataSetChanged()
|
||||
db.delete(sms)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = MainActivity::class.java.simpleName
|
||||
const val MY_PERMISSIONS_REQUEST_READ_CONTACTS = 1
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
package hu.yvan.smsproxy.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import hu.yvan.smsproxy.R
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.settings_activity)
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, SettingsFragment())
|
||||
.commit()
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
|
||||
class SettingsFragment : PreferenceFragmentCompat() {
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@ package hu.yvan.smsproxy.db
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
@Database(entities = arrayOf(SMS::class), version = 1)
|
||||
@Database(entities = arrayOf(SMS::class), version = 2)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun smsDao(): SMSDao
|
||||
}
|
||||
|
||||
@ -5,15 +5,17 @@ import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "pending_sms")
|
||||
data class SMS (
|
||||
@ColumnInfo(name = "contact") val contact: String?,
|
||||
@ColumnInfo(name = "message") val message: String?,
|
||||
@ColumnInfo(name = "timestamp") val timestamp: String?,
|
||||
@ColumnInfo(name = "direction") val direction: Boolean?
|
||||
data class SMS(
|
||||
@ColumnInfo(name = "contact") val contact: String,
|
||||
@ColumnInfo(name = "message") val message: String,
|
||||
@ColumnInfo(name = "timestamp") val timestamp: Long,
|
||||
@ColumnInfo(name = "direction") val direction: Boolean
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true) val id: Int? = null
|
||||
@PrimaryKey(autoGenerate = true) var id: Long = 0
|
||||
|
||||
companion object {
|
||||
const val DIRECTION_SENT = false
|
||||
const val DIRECTION_RECEIVED = true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,15 +13,18 @@ interface SMSDao {
|
||||
@Query("SELECT * FROM pending_sms WHERE id IN (:smsIds)")
|
||||
fun loadAllByIds(smsIds: IntArray): List<SMS>
|
||||
|
||||
// @Query("SELECT * FROM sms WHERE first_name LIKE :first AND last_name LIKE :last LIMIT 1")
|
||||
// fun findByName(first: String, last: String): SMS
|
||||
|
||||
@Query("SELECT * FROM pending_sms WHERE id = :id")
|
||||
fun findById(id: Int): SMS
|
||||
fun findById(id: Long): SMS
|
||||
|
||||
@Insert
|
||||
fun insert(sms: SMS): Long
|
||||
|
||||
@Insert
|
||||
fun insertAll(vararg sms: SMS)
|
||||
|
||||
@Delete
|
||||
fun delete(sms: SMS)
|
||||
|
||||
@Query("DELETE FROM pending_sms WHERE id = :id")
|
||||
fun delete(id: Long)
|
||||
}
|
||||
|
||||
@ -5,18 +5,23 @@ import android.content.Intent
|
||||
import android.content.Context
|
||||
import android.telephony.SmsMessage
|
||||
import android.util.Log
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.room.Room
|
||||
import hu.yvan.smsproxy.SmsPersistedEvent
|
||||
import hu.yvan.smsproxy.db.AppDatabase
|
||||
import hu.yvan.smsproxy.db.SMS
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import java.lang.Exception
|
||||
|
||||
private const val SMS_RECEIVED_ACTION = "hu.yvan.smsproxy.service.action.SMS_RECEIVED"
|
||||
private const val SMS_RESEND_ACTION = "hu.yvan.smsproxy.service.action.SMS_RESEND"
|
||||
|
||||
private const val EXTRA_PARAM_ID = "hu.yvan.smsproxy.service.extra.ID"
|
||||
private const val EXTRA_PARAM_CONTACT = "hu.yvan.smsproxy.service.extra.CONTACT"
|
||||
private const val EXTRA_PARAM_MESSAGE = "hu.yvan.smsproxy.service.extra.MESSAGE"
|
||||
private const val EXTRA_PARAM_TIMESTAMP = "hu.yvan.smsproxy.service.extra.TIMESTAMP"
|
||||
|
||||
private const val SMS_ENPOINT = "https://sms-store.yvan.hu/store/sent/{{uniquehash}}"
|
||||
private const val API_URI_BASE = "%s://%s/store/received/%s"
|
||||
|
||||
/**
|
||||
* An [IntentService] subclass for handling asynchronous task requests in
|
||||
@ -27,42 +32,68 @@ class SMSManager : IntentService("SMSManager") {
|
||||
override fun onHandleIntent(intent: Intent?) {
|
||||
when (intent?.action) {
|
||||
SMS_RECEIVED_ACTION -> {
|
||||
val contact = intent.getStringExtra(EXTRA_PARAM_CONTACT)
|
||||
val message = intent.getStringExtra(EXTRA_PARAM_MESSAGE)
|
||||
val timestamp = intent.getStringExtra(EXTRA_PARAM_TIMESTAMP)
|
||||
val contact = intent.getStringExtra(EXTRA_PARAM_CONTACT) as String
|
||||
val message = intent.getStringExtra(EXTRA_PARAM_MESSAGE) as String
|
||||
val timestamp = intent.getLongExtra(EXTRA_PARAM_TIMESTAMP, 0)
|
||||
handleActionSMSReceived(contact, message, timestamp)
|
||||
}
|
||||
SMS_RESEND_ACTION -> {
|
||||
val id = intent.getLongExtra(EXTRA_PARAM_ID, 0)
|
||||
val contact = intent.getStringExtra(EXTRA_PARAM_CONTACT) as String
|
||||
val message = intent.getStringExtra(EXTRA_PARAM_MESSAGE) as String
|
||||
val timestamp = intent.getLongExtra(EXTRA_PARAM_TIMESTAMP, 0)
|
||||
handleActionSMSReceived(id, contact, message, timestamp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleActionSMSReceived(contact: String?, message: String?, timestamp: String?) {
|
||||
private fun handleActionSMSReceived(id: Long, contact: String, message: String, timestamp: Long) {
|
||||
if (sendHttpRequest(id, contact, message, timestamp)) {
|
||||
Log.d(TAG, "messageid: $id")
|
||||
EventBus.getDefault().post(SmsPersistedEvent(id))
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleActionSMSReceived(contact: String, message: String, timestamp: Long) {
|
||||
val sms = SMS(contact, message, timestamp, SMS.DIRECTION_RECEIVED)
|
||||
val db = Room.databaseBuilder(this, AppDatabase::class.java, "sms_storage").build()
|
||||
db.smsDao().insertAll(sms)
|
||||
val smsId = db.smsDao().insert(sms)
|
||||
if (sendHttpRequest(smsId, sms.contact, sms.message, sms.timestamp)) {
|
||||
db.smsDao().delete(smsId)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendHttpRequest(id: Long, contact: String, message: String, timestamp: Long): Boolean {
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
try {
|
||||
Log.d(TAG, "sending POST request")
|
||||
val response = khttp.post(
|
||||
SMS_ENPOINT,
|
||||
API_URI_BASE.format(
|
||||
if (prefs.getBoolean("api_secure", true)) "https" else "http",
|
||||
prefs.getString("api_url",""),
|
||||
prefs.getString("api_key","")
|
||||
),
|
||||
headers = mapOf("content-type" to "application/json"),
|
||||
json = mapOf(
|
||||
"contactName" to sms.contact,
|
||||
"contactNumber" to sms.contact,
|
||||
"when" to sms.timestamp,
|
||||
"text" to sms.message
|
||||
"id" to id,
|
||||
"contactName" to contact,
|
||||
"contactNumber" to contact,
|
||||
"when" to "@" + timestamp.div(1000),
|
||||
"text" to message
|
||||
)
|
||||
)
|
||||
if (response.statusCode == 200) {
|
||||
db.smsDao().delete(sms)
|
||||
}
|
||||
return response.statusCode == 200
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "khttp: " + e.localizedMessage)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TAG = SMSManager::class.java.simpleName
|
||||
|
||||
/**
|
||||
* Starts this service to perform action Foo with the given parameters. If
|
||||
* Starts this service to perform action SMSRecieved with the given parameters. If
|
||||
* the service is already performing a task this action will be queued.
|
||||
*
|
||||
* @see IntentService
|
||||
@ -77,5 +108,23 @@ class SMSManager : IntentService("SMSManager") {
|
||||
}
|
||||
context.startService(intent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts this service to perform action SMSResend with the given parameters. If
|
||||
* the service is already performing a task this action will be queued.
|
||||
*
|
||||
* @see IntentService
|
||||
*/
|
||||
@JvmStatic
|
||||
fun startActionSMSResend(context: Context, sms: SMS) {
|
||||
val intent = Intent(context, SMSManager::class.java).apply {
|
||||
action = SMS_RESEND_ACTION
|
||||
putExtra(EXTRA_PARAM_ID, sms.id)
|
||||
putExtra(EXTRA_PARAM_CONTACT, sms.contact)
|
||||
putExtra(EXTRA_PARAM_MESSAGE, sms.message)
|
||||
putExtra(EXTRA_PARAM_TIMESTAMP, sms.timestamp)
|
||||
}
|
||||
context.startService(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,11 +10,11 @@ import android.util.Log
|
||||
class SMSReceiver : BroadcastReceiver() {
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Log.i(TAG, "Broadcast received: " + intent.action)
|
||||
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION == intent.action) {
|
||||
Log.i(TAG, "Processing incoming SMS")
|
||||
val intentExtras = intent.extras
|
||||
val format = intentExtras?.getString("format")
|
||||
val pdus: Array<Any>? = intentExtras?.get(PDU_TYPE) as Array<Any>?
|
||||
@Suppress("UNCHECKED_CAST") val pdus: Array<Any>? = intentExtras?.get(PDU_TYPE) as Array<Any>?
|
||||
(0 until pdus!!.size).forEach { i ->
|
||||
val smsMessage = SmsMessage.createFromPdu(pdus[i] as ByteArray, format)
|
||||
SMSManager.startActionSMSRecieved(context, smsMessage)
|
||||
|
||||
48
app/src/main/res/layout/activity_main.xml
Normal file
48
app/src/main/res/layout/activity_main.xml
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.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"
|
||||
android:fitsSystemWindows="true"
|
||||
tools:context=".activity.MainActivity">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/app_bar"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_height="@dimen/app_bar_height"
|
||||
android:layout_width="match_parent"
|
||||
android:theme="@style/AppTheme.AppBarOverlay">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:id="@+id/toolbar_layout"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:toolbarId="@+id/toolbar"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed"
|
||||
app:contentScrim="?attr/colorPrimary">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout_width="match_parent"
|
||||
app:layout_collapseMode="pin"
|
||||
app:popupTheme="@style/AppTheme.PopupOverlay"/>
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<include layout="@layout/content_main"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:layout_anchor="@id/app_bar"
|
||||
app:layout_anchorGravity="bottom|end"
|
||||
app:srcCompat="@android:drawable/ic_menu_preferences"/>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
18
app/src/main/res/layout/content_main.xml
Normal file
18
app/src/main/res/layout/content_main.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.core.widget.NestedScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||
tools:showIn="@layout/activity_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".activity.MainActivity">
|
||||
|
||||
<fragment android:name="hu.yvan.smsproxy.SmsFragment"
|
||||
android:id="@+id/sms_fragment"
|
||||
android:layout_weight="2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
20
app/src/main/res/layout/fragment_sms.xml
Normal file
20
app/src/main/res/layout/fragment_sms.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/item_number"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:textAppearance="?attr/textAppearanceListItem"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/text_margin"
|
||||
android:textAppearance="?attr/textAppearanceListItem"/>
|
||||
</LinearLayout>
|
||||
14
app/src/main/res/layout/fragment_sms_list.xml
Normal file
14
app/src/main/res/layout/fragment_sms_list.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
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:id="@+id/list"
|
||||
android:name="hu.yvan.smsproxy.SmsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
app:layoutManager="LinearLayoutManager"
|
||||
tools:context=".SmsFragment"
|
||||
tools:listitem="@layout/fragment_sms"/>
|
||||
9
app/src/main/res/layout/settings_activity.xml
Normal file
9
app/src/main/res/layout/settings_activity.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
android:id="@+id/settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
</LinearLayout>
|
||||
9
app/src/main/res/menu/menu_main.xml
Normal file
9
app/src/main/res/menu/menu_main.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<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="hu.yvan.smsproxy.activity.MainActivity">
|
||||
<item android:id="@+id/action_settings"
|
||||
android:title="@string/action_settings"
|
||||
android:orderInCategory="100"
|
||||
app:showAsAction="never"/>
|
||||
</menu>
|
||||
5
app/src/main/res/values/dimens.xml
Normal file
5
app/src/main/res/values/dimens.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<resources>
|
||||
<dimen name="app_bar_height">180dp</dimen>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
<dimen name="text_margin">16dp</dimen>
|
||||
</resources>
|
||||
@ -1,3 +1,17 @@
|
||||
<resources>
|
||||
<string name="app_name">SMS Proxy Application</string>
|
||||
<string name="title_activity_main">SMS Proxy</string>
|
||||
|
||||
<string name="action_settings">Settings</string>
|
||||
<string name="title_activity_settings">Settings</string>
|
||||
|
||||
<!-- Preference Titles -->
|
||||
<string name="general_header">API</string>
|
||||
|
||||
<!-- Messages Preferences -->
|
||||
<string name="api_url">Server address</string>
|
||||
<string name="api_key">User key</string>
|
||||
<string name="api_secure">Use HTTPS</string>
|
||||
<string name="api_secure_on">Yes</string>
|
||||
<string name="api_secure_off">No</string>
|
||||
</resources>
|
||||
|
||||
@ -7,5 +7,11 @@
|
||||
<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.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light"/>
|
||||
|
||||
</resources>
|
||||
|
||||
43
app/src/main/res/xml/root_preferences.xml
Normal file
43
app/src/main/res/xml/root_preferences.xml
Normal file
@ -0,0 +1,43 @@
|
||||
<!--
|
||||
~ Copyright 2018 The app 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.
|
||||
-->
|
||||
|
||||
<androidx.preference.PreferenceScreen
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/general_header">
|
||||
|
||||
<EditTextPreference
|
||||
app:key="api_url"
|
||||
app:title="@string/api_url"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<EditTextPreference
|
||||
app:key="api_key"
|
||||
app:title="@string/api_key"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
app:key="api_secure"
|
||||
app:title="@string/api_secure"
|
||||
app:summaryOn="@string/api_secure_on"
|
||||
app:summaryOff="@string/api_secure_off"
|
||||
app:dependency="api_url"
|
||||
app:defaultValue="true" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@ -1,14 +1,13 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.31'
|
||||
ext.kotlin_version = '1.3.41'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.4.2'
|
||||
classpath 'com.android.tools.build:gradle:3.5.0'
|
||||
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
|
||||
@ -19,7 +18,7 @@ allprojects {
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,6 @@
|
||||
#Fri Aug 16 09:44:48 CEST 2019
|
||||
#Wed Aug 21 14:27:08 CEST 2019
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user