Kotlin code Send SMS from within App without using default app - kotlin

I am trying to build an app whereby the user clicks a submit button which will send the contents of their input via SMS to a predefined number. Being very new to Kotlin, I have been helped with the code to send the data via SMS, however it opens up the default messaging app and the user has to interact with the messaging app and then navigate back to my app. What I would like is for this to happen in the background and send directly from my app. The code is below...Any help greatly appreciated, Many thanks
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val backbut = findViewById<Button>(R.id.backbut)
backbut.setOnClickListener {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
}
var spinner: Spinner? = null
spinner = this.spinner
val sub1: Button = findViewById<Button>(R.id.sub1)
sub1.setOnClickListener {
val cust: String = cust.text.toString()
val reg: String = reg.text.toString()
val pal: String = pal.text.toString()
val cont:String = cont.text.toString()
val data: String =
"CUSTOMER : ".plus(cust).plus("\n").plus("CONTAINER : ").plus(cont).plus("\n").plus("VEH
REG : ").plus(reg).plus("\n").plus("PALLETS : ")
.plus(pal)
startActivity(getSendSmsIntent("1234567", data))
}
}
// textview_selected!!.text = "Selected : "+ Spinner [position]
private fun getSendSmsIntent(phoneNumber: String, content: String?): Intent? {
val uri = Uri.parse("smsto:$phoneNumber")
val intent = Intent(Intent.ACTION_SENDTO, uri)
intent.putExtra("sms_body", content)
return getIntent(intent, true)
}
private fun getIntent(intent: Intent, isNewTask: Boolean): Intent? {
return if (isNewTask) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) else intent
}
}

After reading the documentation, I think you can achieve your needs using the following code :
private fun sendSMS(phoneNumber: String, message: String) {
val sentPI: PendingIntent = PendingIntent.getBroadcast(this, 0, Intent("SMS_SENT"), 0)
SmsManager.getDefault().sendTextMessage(phoneNumber, null, message, sentPI, null)
}
Add this permission to your AndroidManifest and make sure it's granted :
<uses-permission android:name="android.permission.SEND_SMS" />
Call sendSMS method as follows :
sendSMS("+2126000000", "Some text here")
Screenshot :

Related

How to send data another page and list with kotlin?

I just started learning Kotlin. I am making an application that saves bank (IBAN) information. I save the information locally using sharedpreferences.
I save the information to the list and save it as sharedpreferences.
Information is recorded on page 2 and I want to list this recorded information on page 1.
I was doing this simply in Flutter, but I couldn't understand how to do it in Kotlin.
package com.example.ibansfer
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.ibansfer.databinding.ActivityAddIbanBinding
import com.example.ibansfer.models.IbanModel
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
class AddIbanActivity : AppCompatActivity() {
private lateinit var binding: ActivityAddIbanBinding
private var ibanList: ArrayList<IbanModel> = ArrayList()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAddIbanBinding.inflate(layoutInflater)
setContentView(binding.root)
setTitle("IBAN bilgisi ekle")
getSupportActionBar()?.setDisplayHomeAsUpEnabled(true);
val sharedPreferences = this.getSharedPreferences("ibans", MODE_PRIVATE)
val editor = sharedPreferences.edit()
fun saveData() {
val gson = Gson()
val json = gson.toJson(ibanList)
editor.putString("ibans", json)
editor.apply()
}
binding.ibanSaveBttn.setOnClickListener {
val ibanOwner = binding.ibanOwner.text.toString()
val bankName = binding.bankName.text.toString()
val ibanAdress = binding.ibanAdress.text.toString()
if (ibanOwner.isEmpty() || bankName.isEmpty() || ibanAdress.isEmpty()) {
Toast.makeText(this, "Lütfen tüm alanları doldurunuz.", Toast.LENGTH_LONG).show()
} else {
ibanList.add(IbanModel(ibanOwner, bankName, ibanAdress))
saveData()
Toast.makeText(this, "IBAN bilgileri başarıyla eklendi.", Toast.LENGTH_LONG).show()
finish()
}
}
}
}
If you save the data in SharedPrefferences, you can always retrieve it back in the other screen.
val sharedPref = activity?.getPreferences("ibans", Context.MODE_PRIVATE) ?: return
val myString = sharedPref.getString("ibans", defaultValue)
You can even set up a SharedPrefferences listener that will get notified whenever new data is added to it and act accordingly.
val sharedPreferencesListener =
SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
// code to execute on changes here
}
activity?.getPreferences("ibans", Context.MODE_PRIVATE)
?.registerOnSharedPreferenceChangeListener(sharedPreferencesListener )
Also don't forget to unregister using unregisterOnSharedPreferenceChangeListener
Or alternatively, use Intents as the comment suggests to pass data between Activities/Fragments.

lateinit property binding has not been initialized though i did not set it as lateinit

I faced that error when i was trying to update my views with new ViewBinding stuff. I don't define the value as "lateinit" but logccat says "lateinit property binding has not been initialized" why i m taking this ?
Thanks in advance.
The exception is on private val email and password rows.
class MainActivity : AppCompatActivity() {
private lateinit var auth : FirebaseAuth
private lateinit var binding: ActivityMainBinding
private val email = binding.emailText.text.toString()
private val password = binding.passwordText.text.toString()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
auth= FirebaseAuth.getInstance()
val guncelKullanici = auth.currentUser
if (guncelKullanici!= null) {
val intent = Intent(this, haber_akisi::class.java)
startActivity(intent)
finish()
}
}
fun girisYap ( view: View) {
if (email.isNotBlank() && password.isNotBlank()) {
auth.signInWithEmailAndPassword(email,password)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
val intent = Intent(this,haber_akisi::class.java)
startActivity(intent)
finish()
}
}.addOnFailureListener { exception ->
Toast.makeText(this,exception.localizedMessage,Toast.LENGTH_LONG).show()
}}else {
Toast.makeText(this,"Lütfen E-mail ve Password alanlarını doldurunuz",Toast.LENGTH_LONG).show()
}
}
fun kayitOl ( view : View) {
if ( email.isNotBlank() && password.isNotBlank() ) {
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
val intent = Intent(this, haber_akisi::class.java)
startActivity(intent)
finish()
}
}.addOnFailureListener { exception ->
Toast.makeText(this, exception.localizedMessage, Toast.LENGTH_LONG).show()
}
}else {
Toast.makeText(this,"Lütfen E-mail ve Password alanlarını doldurunuz",Toast.LENGTH_LONG).show()
}
}
}
This is because private val email = binding.emailText.text.toString() is using the "binding" variable before it has been initialized. The error is saying that the "lateinit var binding" has not been initialized yet but you are accessing it on private val email = binding.emailText.text.toString()
Edit: One way to solve this is to make email and password as lateinit vars too. Another way is to not have an email and password class level properties and just access the binding where it's needed like in girisYap() and kayitOl()
You are accessing binding(ActivityMainBinding Identifier) in the next lines, after its declaration.
You need to initialize binding before using it.

LiveData observation won't update

I want to send some data to the server and show its response to the user.
I'm using MVVM so I created a repository like this:
class Repository {
fun getData(context: Context, word: String): LiveData<String> {
val result = MutableLiveData<String>()
val request = object : StringRequest(
Method.POST,
"https://.......",
Response.Listener {
result.value = it.toString()
},
Response.ErrorListener {
result.value = it.toString()
}) {
#Throws(AuthFailureError::class)
override fun getParams(): MutableMap<String, String> {
val params = HashMap<String, String>()
params["word"] = word
return params
}
}
val queue = Volley.newRequestQueue(context)
queue.add(request)
return result
}
}
which just sends 'word' to the server and get its response.
my view model class contains just a mutableLiveData and a function. it is like this:
class ViewModel(application: Application) : AndroidViewModel(application) {
var result = MutableLiveData<String>()
fun getData(word: String): LiveData<String> {
val repository = Repository()
result = repository.getData(getApplication(), word) as MutableLiveData<String>
return result
}
}
I set an observation for result in my main Activity, therefore it is my MainActivity codes:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val model = ViewModelProviders.of(this).get(ViewModel::class.java)
submit.setOnClickListener {
model.getData(search_txt.text.toString())
}
model.result.observe(this, Observer {
Log.i("Log", "observe is :$it")
text.text = it
})
}
but it doesn't work! I get the user's input using an edit text and after pressing a button, I call getData function which is in my View Model class. but it returns always null and observation won't work.
I try to put observe the method in my button listener, in this way I get the result but it seems it's not a correct way because after I rotate my phone, all data ware gone and I need to fetch data from the server again while it shouldn't.

retrofit Give kotlin.KotlinNullPointerException

Data get from the Sql server and get data json. this json data parsing retofit2.
Created Login Activity but its give error
MainActivity.kt
class MainActivity : AppCompatActivity() {
internal lateinit var api : APIInterface
private var compositeDisposable : CompositeDisposable? = null
var userName : String? = null
var password : String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnLogin.setOnClickListener {
userName = tvUsername.text.toString()
password = tvPassword.text.toString()
getUserName(userName!!,password!!)
}
}
fun getUserName(user : String, pass : String){
val retrofit = APIClient.apIClient
if (retrofit != null) {
api = retrofit.create(APIInterface::class.java)
}
compositeDisposable!!.add(api.getLoginData(user, pass)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
if (it.success.equals(1)){
val intent = Intent(this,Company::class.java)
startActivity(intent)
Toast.makeText(this,"Login Successfully!!!",Toast.LENGTH_LONG).show()
}else{
Toast.makeText(this,"UserName or Password is Wrong!!!",Toast.LENGTH_LONG).show()
}
},{
Toast.makeText(this, it.message, Toast.LENGTH_LONG).show()
})
)
}
}
when Debbuger reached on compositeDisposable!!.add(api.getLoginData(user, pass) it's give Error kotlin.kotlinNullPointerException
RestApi Url :
http://localhost/Account/Login.php?user=ABC&pass=1
APIClient.kt
object APIClient {
val BASE_URL = "http://10.0.2.2/Account/"
var retrofit:Retrofit? = null
val apIClient:Retrofit?
get() {
if (retrofit == null)
{
retrofit = Retrofit.Builder().
baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build()
}
return retrofit
}
}
APIInterface.kt
interface APIInterface {
#GET("Login.php")
fun getLoginData(#Query("user") user : String,
#Query("pass") pass : String) : Observable<LoginList>
}
The most likely cause for the NullPointerException is that compositeDisposable is null.
At the beginning of MyActivity that variable is initialised to null and then it's never changed, so when you use the !! operator the exception is thrown.
I think you can initialise compositeDisposable directly with the correct value, i.e. something like val compositeDisposable = CompositeDisposable().
Also, val should be preferred over var whenever possible – as immutability is easier to control – and userName and password could probably be local variable or at least private

hide Alert Dialog in kotlin

My current project downloading data from a server time I want to display a progress bar so the user knows what is going on. I have a simple alert dialog , l am try to add alert dialog when data json loading for user . when l launching app the alert dialog stay stick on screen even if the data loaded already and doesn't hide .
AsyncTask code :
inner class Arr : AsyncTask<String, String, String>(){
val progressDialog = AlertDialog.Builder(this#MainActivity)
val dialogView = layoutInflater.inflate(R.layout.progress_dialog,null)
val message = dialogView.findViewById<TextView>(R.id.message_id)
val dialog = progressDialog.create()
override fun onPreExecute() {
super.onPreExecute()
progressDialog.setMessage("loading")
progressDialog.setCancelable(false)
progressDialog.show()
}
// for build connection
override fun doInBackground(vararg url: String?): String{
var text : String
val connection = URL(url[0]).openConnection() as HttpURLConnection
try {
connection.connect()
text = connection.inputStream.use { it.reader().use{reader -> reader.readText()} }
} finally{
connection.disconnect()
}
return text
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
handleJson(result)
dialog.dismiss()
}
override fun onProgressUpdate(vararg text: String?) {
dialog.dismiss()
}
private fun handleJson (jsonString: String?){
dialog.dismiss()
val jsonObj = JSONObject(jsonString)
val result = jsonObj.getJSONObject("result")
val response = result.getJSONObject("response")
val airport = response.getJSONObject("airport")
val pluginData = airport.getJSONObject("pluginData")
val schedule = pluginData.getJSONObject("schedule")
val arrivals = schedule.getJSONObject("arrivals")
// val data = arrivals.getJSONObject("data")
val jsonArray = JSONArray(arrivals.get("data").toString())
val list = ArrayList<FlightShdu>()
var x = 0
while (x < jsonArray.length()){
val jsonObject = jsonArray.getJSONObject(x)
list.add(FlightShdu(
jsonObject.getJSONObject("flight").getJSONObject("identification").getJSONObject("number").getString("default"),
jsonObject.getJSONObject("flight").getJSONObject("airline").getString("name"),
jsonObject.getJSONObject("flight").getJSONObject("status").getString("text"),
jsonObject.getJSONObject("flight").getJSONObject("airline").getJSONObject("code").getString("icao"),
jsonObject.getJSONObject("flight").getJSONObject("time").getJSONObject("scheduled").getString("arrival")
))
x++
}
list.forEach(::println)
val adapter = ListAdapte(this#MainActivity,list)
flight_arrivel_list.adapter = adapter
}
} //
any solution please ?
Change to this:
override fun onPreExecute() {
super.onPreExecute()
dialog.setMessage("loading")
dialog.setCancelable(false)
dialog.show()
}
and hide it with:
dialog.dismiss();
you must refer to the AlertDialog object and not the AlertDialog.Builder.
In your onPreExecute()
override fun onPreExecute() {
...
progressDialog.show()
}
But in onPostExecute() you call different dialog to dismiss
override fun onPostExecute(result: String?) {
...
dialog.dismiss()
}
So you need to call progressDialog.dismiss() in onPostExecute().
progressDialog.dismiss() instead of dialog.dismiss()