How to detect bluetooth device connection in Kotlin? - kotlin

I am trying to show toast message when the device is connected to bluetooth. To do this, I made a receiver and wrote the code as below, but there is no response when a Bluetooth device is connected.
AndroidManifest.xml
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
mainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val bluetoothBroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context?, intent: Intent?) {
val bleOnOffBtn:ToggleButton = findViewById(R.id.bluetooth_on_off_btn)
var action = intent?.getAction()
// toast not showing for connecting and disconnecting device
if(action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)){
Toast.makeText(
baseContext,
"Device is now Connected",
Toast.LENGTH_SHORT
).show()
}else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
Toast.makeText(
baseContext,
"Device is disconnected",
Toast.LENGTH_SHORT
).show()
}
}
}
val filter = IntentFilter().apply{
addAction(BluetoothAdapter.ACTION_STATE_CHANGED)
addAction(BluetoothDevice.ACTION_ACL_CONNECTED)
addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED)
addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED)
}
registerReceiver(bluetoothBroadcastReceiver, filter)
}
What part of the code below should be modified to show toast when a Bluetooth device is connected?

It didn't work because I didn't ask for permission grant.
I write By inserting the code below into MainActivity.kt to allow permission, the desired event occurs when the device is connected.
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_SMS,Manifest.permission.BLUETOOTH_CONNECT), 2)

Related

android livedata not working in Activity , viewmodel

Hello I have recently encountered a situation where observing is not possible in livedata, so I am going to ask a question
It's too basic, but I don't know why it doesn't work, so I need your help.
If you give me a little teaching, I would be grateful
my SignUpActivity
class SignUpActivity : BaseKotlinActivity<ActivitySignUpBindingImpl, SignUpViewModel>() {
override val layoutResourceId: Int get() = R.layout.activity_sign_up
override val viewModel: SignUpViewModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = DataBindingUtil.setContentView<ActivitySignUpBindingImpl>(this, layoutResourceId)
binding.apply {
lifecycleOwner = this#SignUpActivity
signUpViewModel = viewModel
}
viewModel?.apply {
signUpStep.observe(this#SignUpActivity, Observer {
when (it) {
SignUpStep.SIGN_UP -> supportFragmentManager.beginTransaction().replace(R.id.fragment, SignUpFragment(), "SignUpFragment").commit()
SignUpStep.PASSWORD -> supportFragmentManager.beginTransaction().replace(R.id.fragment, SignUpPasswordFragment(), "SignUpPasswordFragment").commit()
SignUpStep.PHONE_CERTIFICATION -> supportFragmentManager.beginTransaction().replace(R.id.fragment, SignUpPhoneCertificationFragment(), "SignUpPhoneCertificationFragment").commit()
else -> Unit
}
Log.d("Test Checked1", "${signUpStep.value}")
})
}
}
}
my viewModel
private val _signUpStep = MutableLiveData<SignUpStep>(SignUpStep.SIGN_UP)
val signUpStep: LiveData<SignUpStep>
get() = _signUpStep
fun moveStep(view: View, newSignUpStep: SignUpStep) {
val oldSignUpStep = _signUpStep.value
_signUpStep.value = newSignUpStep
Log.d( "Test Checked","moveStep: $oldSignUpStep -> $newSignUpStep")
}
log
Test Checked1: SIGN_UP
moveStep: SIGN_UP -> PASSWORD
moveStep: PASSWORD -> PASSWORD
moveStep: PASSWORD -> PASSWORD
If you check the log, you can see that the moveStep changes normally. Then signUpSteop has changed normally, but it is not received in the observe of livedata, because the screen does not move and the log does not appear.
I'm just wondering if the code is wrong or what's wrong. Can you help me?
For reference, signUpStep is changing in Fragment and livedata is constantly being observed in activity.

New to coding; Can't get button to link to new activity in Kotlin

It opens the first activity on the emulator, but fails on button click. I created the second activity (AddProductActivity), so maybe I did something wrong there. I've tried all the variables I could find online to change how the button operates.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.content_main)
val button = findViewById<Button>(R.id.goToAddProduct)
button.setOnClickListener {
val intent = Intent(this, AddProductActivity::class.java)
startActivity(intent)
}
}
}
class AddProductActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.add_product)
}
}
on content_main.xml:
<Button
android:id="#+id/goToAddProduct"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/add_to_inventory"/>
Make sure you have registered your new activity in the manifest. This is a common mistake by newcomers.
If that is not the case before you click on the button open your logcat view in android studio. Once you click on the button please investigate the crash issue from here.

How to "android media player" (Kotlin)

Here's the situation - I've started studying kotlin and android studio, and now I'm stuck with this.
I have a button (ImageView) that when pressed starts to play an audio file.
class MainActivity : AppCompatActivity() {
private var mp: MediaPlayer? = null
private var bruhSound: MutableList<Int> = mutableListOf(R.raw.bruh)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
bruhBtn.setOnClickListener {
if (mp == null) {
controlSound(bruhSound[0])
bruhBtn.setImageResource(R.drawable.btnpressed)
} else if (mp !== null) {
bruhBtn.setImageResource(R.drawable.btn)
}
}
}
private fun controlSound(id: Int) {
if (mp == null) {
mp = MediaPlayer.create(this, id)
Log.d("MainActivity", "ID: ${mp!!.audioSessionId}")
}
mp?.start()
Log.d("MainActivity", "Duration: ${mp!!.duration / 1000} seconds")
}
Currently when I press "bruhBtn", the picture is changing to "btnpressed" and back again correctly, but it wont change after audio is ended. I want it to reset on the audio finishing. I realize that problem is with my code, I need to change the image when the audio is finished. How would I do this?
Before your line
mp?.start
add a listener
mp?.setOnCompletionListener { //change your button state here }

Android SettingsActivity popuate ListPreference programatically

How can I populate the items of a ListPreference programatically rather than statically from arrays.xml?
SettingsActivity.kt
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)
// Do something here to populate the ListPreference bluetoothName...
}
class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
// ... or here?
// (WTF is a Fragment anyway?)
}
}
}
root_preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen
xmlns:app="http://schemas.android.com/apk/res-auto">
<androidx.preference.ListPreference
app:dialogTitle="Select bluetooth adapter"
app:key="bluetoothName"
app:summary="%s"
app:title="Bluetooth adapter" />
<androidx.preference.ListPreference
app:dialogTitle="Select units"
app:entries="#array/units_names"
app:entryValues="#array/units_values"
app:key="units"
app:summary="%s"
app:title="Units"
/>
</androidx.preference.PreferenceScreen>
This seems to work for populating the items, but the app crashes when the user selects one
Process: com.rwb.psamfd, PID: 23596
java.lang.ArrayIndexOutOfBoundsException: length=0; index=1
at androidx.preference.ListPreferenceDialogFragmentCompat.onDialogClosed(ListPreferenceDialogFragmentCompat.java:105)
at androidx.preference.PreferenceDialogFragmentCompat.onDismiss(PreferenceDialogFragmentCompat.java:265)
at androidx.fragment.app.DialogFragment$3.onDismiss(DialogFragment.java:120)
at android.app.Dialog$ListenersHandler.handleMessage(Dialog.java:1323)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
and fuck knows what that means.
You seem to have to give the ListPreference an #array/ otherwise you get IllegalStateException: ListPreference requires an entries array and an entryValues array.
<androidx.preference.ListPreference
app:dialogTitle="Select bluetooth adapter"
app:key="bluetoothName"
app:entries="#array/empty"
app:entryValues="#array/empty"
app:summary="%s"
app:title="Bluetooth adapter" />
<string-array name="empty"></string-array>
class SettingsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// get bluetooth devices
var cs: Array<CharSequence> = arrayOf("")
try {
val bt: BluetoothManager =
getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager;
val bta: BluetoothAdapter = bt.adapter;
val pairedDevices: Set<BluetoothDevice> = bta.bondedDevices
cs = pairedDevices.map { z -> z.name }.toTypedArray()
}
catch(e:Exception) {}
// Start the fragment
setContentView(R.layout.settings_activity)
supportFragmentManager
.beginTransaction()
.replace(R.id.settings, SettingsFragment(cs))
.commit()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
}
class SettingsFragment(adapters: Array<CharSequence>) : PreferenceFragmentCompat() {
private var adapters: Array<CharSequence> = adapters
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
val p:ListPreference? = findPreference<ListPreference>("bluetoothName")
p?.setEntries(adapters)
}
}
}
Turns out you need
p?.setEntryValues(adapters)
as well.

Button onClick attribute is none if activity written in Kotlin

Follow this tutorial: Android - Start Another Activity if I made MainActivity.java button OnClick attribute has the sendMessage() method.
But if I made MainActivity.kt button OnClick attribute has nothing to show, just a none.
Is this an Android Studio 3 bug or I missed something for Kotlin?
Java mainActivity:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
/** Called when the user taps the Send button */
public void sendMessage(View view) {
// Do something in response to button
}
}
Kotlin mainActivity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
/** Called when the user taps the Send button */
fun sendMessage(view: View) {
// Do something in response to button
}
}
XML layout (Java and Kotlin project are the same)
<?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="ir.bigbang.vahid.myapplication.MainActivity">
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
tools:layout_editor_absoluteX="148dp"
tools:layout_editor_absoluteY="81dp" />
</android.support.constraint.ConstraintLayout>
It seems like the designer does not support Kotlin yet. Here are some solution:
XML (Not Recommended)
Add the following line to your Button tag. This is exactly what the designer will do.
android:onClick="sendMessage"
Old Fashion
No need to add anything.
val button = findViewById<Button>(R.id.Button)
button.setOnClickListener {
}
kotlin-android-extensions (Recommended)
Add apply plugin: "kotlin-android-extensions" to your build.gradle
// button is the Button id
button.setOnClickListener {
}
Your code will like this:
button.setOnClickListener(){
Toast.makeText(this#MainActivity, "Its toast!", Toast.LENGTH_SHORT).show();
}
Here import will:
import kotlinx.android.synthetic.main. activity_main.*
Here "button" is the id of that Button in .xml file. Here the advantage is no need to create Button object in your java class.
Once defined the sendMessage class as :
/** Called when the user taps the Send button */
fun sendMessage(view: View) {
setContentView(R.layout.activity_second)
// Do something in response to button
}
And also defined a second activity as:
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
}
}
I added the SendMessage to the OnClick function:
And then it worked.
You can easily define this inside the XML itself. But using the android:onClick attribute is still a little expensive.
Instead you could consider using the Kotlin Android Extensions and synthetic properties:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
// Do something in response to button
}
}
Button OnClick implementation it's can be done by some ways in Android
some of the possible ways are below in sample:
1>Using OnClickListener as a interface
Here we implement our main activity with OnClicklistener
and override the function onClick
override fun onClick(v: View?) {
when (v?.id){
(R.id.btn1) -> {
toastmsg("Button1");
}
R.id.btn2 -> {
toastmsg("Button2");
}
}
}
2>And create a function and pass the OnClickListener with
variable sample:
findViewById<Button>(R.id.btn3).setOnClickListener(btnClick);
var btnClick =
OnClickListener {
Toast.makeText(this, "BtnClick", Toast.LENGTH_SHORT).show() ;
}
3>Create OnClickListener in Oncreate()
btn1=findViewById(R.id.btn1);
btn1?.setOnClickListener {
toastmsg("test button1");
}
full sample Code of the example it contains all the possible implementation of the Button OnClickListener :
class MainActivity : AppCompatActivity() , OnClickListener{
lateinit var tv1:TextView;
lateinit var tv2:TextView;
lateinit var tv3:TextView;
var btn1: Button? =null;
var btn2: Button? =null;
var btn3: Button? =null;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn1=findViewById(R.id.btn1);
btn1?.setOnClickListener {
toastmsg("test button1");
}
findViewById<Button>(R.id.btn2).setOnClickListener(this);
findViewById<Button>(R.id.btn3).setOnClickListener(btnClick);
}
var btnClick =
OnClickListener {
Toast.makeText(this, "BtnClick", Toast.LENGTH_SHORT).show() ;
}
override fun onClick(v: View?) {
when (v?.id){
(R.id.btn1) -> {
toastmsg("Button1");
}
R.id.btn2 -> {
toastmsg("Button2");
}
}
}
private fun toastmsg(msg: String){
Toast.makeText(this, "DaggerTest" + msg, Toast.LENGTH_SHORT).show();
}
}
Here's the solution I came up with in the MainActivity.kt file.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
sendMessage()
}
}
/** Called when the user taps the Send button */
private fun sendMessage() {
val editText = findViewById<EditText>(R.id.editText)
val message = editText.text.toString()
val intent = Intent(this, DisplayMessageActivity::class.java).apply
{
putExtra(EXTRA_MESSAGE, message)
}
startActivity(intent)
}