I am a beginner in android application development(Kotlin) and recently I was handover a project on NFT which involves walletConnect integration & for that I am using the walletConnectV1 library.
Fetching the public key and Connecting with metamask was not so hard but I am struggling when it comes to signing methods.
if anyone can help me with, how to sign messages and transactions or what I was doing wrong all this time that would really help me.
Thank you
Connect Button Click Listener
screen_main_connect_button.setOnClickListener {
try {
ExampleApplication.resetSession()
ExampleApplication.session.addCallback(this)
val i = Intent(Intent.ACTION_VIEW, Uri.parse(ExampleApplication.config.toWCUri()))
startActivity(i)
} catch (e: ActivityNotFoundException) {
// open play store
} catch (e: Exception) {
//handle exceptions
}
}
Response after the session was approved
private fun sessionApproved() {
uiScope.launch {
val account = session.approvedAccounts()?.get(0)?:""
screen_main_status.text = "Connected: $account"
screen_main_connect_button.visibility = View.GONE
screen_main_disconnect_button.visibility = View.VISIBLE
screen_main_tx_button.visibility = View.VISIBLE
val job = async {
personalSign(
"Sign this message of mine to this address",
account) {
Log.d(TAG, "sessionApproved: ${it.result}")
}
val intent = Intent(Intent.ACTION_VIEW)
intent.data = Uri.parse("wc:")
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
}
}
private fun personalSign(
message: String,
address: String,
response: (Session.MethodCall.Response) -> Unit
) {
val id = System.currentTimeMillis()
val messageParam = if (message.hasHexPrefix()) message else message.toHex()
session.performMethodCall(
Session.MethodCall.Custom(
id, "personal_sign", listOf(messageParam, address)
)
) { response(it) }
}
Related
i'm actually new to Kotlin android development. I'm making an app that uses Google sheets as a database. My app can successfully run after Google sign in. In fact I want my user to sign in to app, if their email ID is present in the Emails sheet in the Google sheet. So I have done following steps in my code so far.
Sign in user with Google Sign In
Retrieve data from "Emails" sheet in my Google Spreadsheet
Then store them in to a data class (Customers data class in Shipment.kt)
Then I check whether signed in user's email ID available in the data class or not. This is where I need help. It's giving me this error
"Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly."
Can someone help me on this?
Below is my data class in Shipment.kt
package com.example.demoonlinesheet
data class Shipments(
val shipperName:String,
val volume:String,
val eta:String,
val etd:String)
data class Customers(
val companyName:String,
val customerName:String,
val emailID:String)
Below is the code that I have written so far in MainActivity.kt
const val RC_SIGN_IN = 123
const val EXTRA_MESSAGE = "com.example.demoonlinesheet.MESSAGE"
const val EXTRA_MESSAGE2 = "com.example.demoonlinesheet.MESSAGE"
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Configure sign-in to request the user's ID, email address, and basic
// profile. ID and basic profile are included in DEFAULT_SIGN_IN.
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.build()
// Build a GoogleSignInClient with the options specified by gso.
var mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
sign_in_button.setOnClickListener{
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
val acct = GoogleSignIn.getLastSignedInAccount(this)
if (acct != null) {
startActivity(Intent(this, SecondActivity::class.java).apply{
putExtra(EXTRA_MESSAGE, acct.displayName)
//putExtra(EXTRA_MESSAGE2, acct.email)
} )
}
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// Result returned from launching the Intent from GoogleSignInClient.getSignInIntent(...);
if (requestCode == RC_SIGN_IN) {
// The Task returned from this call is always completed, no need to attach
// a listener.
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
handleSignInResult(task)
}
}
private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
val companyList= arrayListOf<Customers>()
val url="https://sheets.googleapis.com/v4/spreadsheets/{sheetID}/values/{sheetName}?alt=json&key={APIKey}"
val queue = Volley.newRequestQueue(this)
val jsonObjectRequest = JsonObjectRequest(Request.Method.GET, url, null,
{
fun onResponse(response: JSONObject) {
try {
// val feedObj = response.getJSONObject("")
val entryArray = response.getJSONArray("values")
for (i in 2 until entryArray.length()) {
val entryObj = entryArray.getJSONArray(i)
val companyName = entryObj[0].toString()
val customerName = entryObj[1].toString()
val emailID = entryObj[2].toString()
// entryObj.getJSONObject("gsx\$lastname").getString("\$t")
companyList.add(Customers(companyName, customerName, emailID))
}
} catch (e: JSONException) {
e.printStackTrace()
}
}
}, {
fun onErrorResponse(error: VolleyError?) {
Toast.makeText(this#MainActivity, "Fail to get data..", Toast.LENGTH_SHORT)
.show()
}
})
queue.add(jsonObjectRequest)
fun checkUser() {
val getAccount = completedTask.getResult(ApiException::class.java)
val emailLoggedIn = getAccount.email.toString()
val companies = listOf<Customers>()
//this is where I get the error message "Type inference failed. The value of the type parameter T should be mentioned in input types (argument types, receiver type or expected type). Try to specify it explicitly."
if (emailLoggedIn in companies){
//do something here
}
try {
val account = completedTask.getResult(ApiException::class.java)
val loggedname = account.displayName
//startActivity(Intent(this#MainActivity, SecondActivity::class.java))
val intent = Intent(this, SecondActivity::class.java).apply {
putExtra(EXTRA_MESSAGE, loggedname)
}
startActivity(intent)
} catch (e: ApiException) {
}
}
}
From your code:
if (emailLoggedIn in companies) {
//do something here
}
emailLoggedIn is a String, companies is a List<Customers>.
How does List know how to compare String and Customers? :)
You need something like this:
if (companies.any { it.emailID == emailLoggedIn }){
//do something here
}
I should also mention that you can leave the if condition unchanged and add the following code that overloads the in keyword:
operator fun List<Customers>.contains(email: String): Boolean {
return this.any { it.emailID == email }
}
But, in my opinion, this overload looks terrible and confusing :)
I have simple button in android jetpack compose, when I click the button, I want to open gmail and send mail to "android#gmail.com", is it possible?
#Composable
fun SimpleButton() {
Button(onClick = {
//your onclick code here
}) {
Text(text = "Simple Button")
}
}
You have to create an Intent and then start an Activity with it, similar to how you would have to do it normally.
The only difference in Compose is that you obtain the Context with LocalContext.current.
#Composable
fun SimpleButton() {
val context = LocalContext.current
Column {
Button(onClick = {
context.sendMail(to = "example#gmail.com", subject = "Some subject")
}) {
Text(text = "Send mail")
}
Button(onClick = {
context.dial(phone = "12345678")
}) {
Text(text = "Dial number")
}
}
}
fun Context.sendMail(to: String, subject: String) {
try {
val intent = Intent(Intent.ACTION_SEND)
intent.type = "vnd.android.cursor.item/email" // or "message/rfc822"
intent.putExtra(Intent.EXTRA_EMAIL, arrayOf(to))
intent.putExtra(Intent.EXTRA_SUBJECT, subject)
startActivity(intent)
} catch (e: ActivityNotFoundException) {
// TODO: Handle case where no email app is available
} catch (t: Throwable) {
// TODO: Handle potential other type of exceptions
}
}
fun Context.dial(phone: String) {
try {
val intent = Intent(Intent.ACTION_DIAL, Uri.fromParts("tel", phone, null))
startActivity(intent)
} catch (t: Throwable) {
// TODO: Handle potential exceptions
}
}
For more possibilities see answers here, but keep in mind that some are outdated.
I am trying to obtain phone number(s) in Jetpack compose following Googles Phone Number Hint Docs. But I am stuck in a problem where it says: getIntentSender() is unresolved in request: GetPhoneNumberHintIntentRequest.
I am also getting another error on addOnFailureListener
Type mismatch.
Required:
OnFailureListener
Found:
Int
#Composable
fun PhoneNumberConsent() {
val context = LocalContext.current
val request = GetPhoneNumberHintIntentRequest.builder().build()
val phoneNumberHintIntentResultLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
) {
try {
val phoneNumber =
Identity.getSignInClient(context)
.getPhoneNumberFromIntent(it.data)
} catch (e: Exception) {
Log.e(TAG, "Phone Number Hint failed")
}
}
Identity.getSignInClient(context)
.getPhoneNumberHintIntent(request)
.addOnSuccessListener(
try {
phoneNumberHintIntentResultLauncher.launch(request.getIntentSender())
} catch (e: Exception) {
Log.e(TAG, "Launching the PendingIntent failed")
} as OnSuccessListener<in PendingIntent>
)
.addOnFailureListener(
Log.e(TAG, "Phone Number Hint failed")
)
}
addOnSuccessListener accepts a listener, which can be passed as trailing closure.
Result passed to this listener is a pending intent which has intentSender property, and it can be used to create IntentSenderRequest.
Here's a working example:
val context = LocalContext.current
val request = GetPhoneNumberHintIntentRequest.builder().build()
val phoneNumberHintIntentResultLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartIntentSenderForResult(),
) {
try {
val phoneNumber = Identity.getSignInClient(context)
.getPhoneNumberFromIntent(it.data)
println("phoneNumber $phoneNumber")
} catch (e: Exception) {
println("Phone Number Hint failed")
e.printStackTrace()
}
}
Button(onClick = {
Identity.getSignInClient(context)
.getPhoneNumberHintIntent(request)
.addOnSuccessListener { pendingIntent ->
try {
phoneNumberHintIntentResultLauncher.launch(
IntentSenderRequest.Builder(
pendingIntent.intentSender
).build()
)
} catch (e: Exception) {
println("Launching the PendingIntent failed")
e.printStackTrace()
}
}
.addOnFailureListener {
println("addOnFailureListener $it")
}
}) {
}
If you need to run it immediately after the view appears, use LaunchedEffect instead of Button.onClick. Your current approach contradicts one of the basic rules of Compose, which is that composable functions must be free of side-effects. Read more in thinking in compose
According to this docs there is no getIntentSender() method in GetPhoneNumberHintIntentRequest class. Maybe there is a typo in the tutorial you are following, try to use result instead of request:
Identity.getSignInClient(context)
.getPhoneNumberHintIntent(request)
.addOnSuccessListener { result ->
try {
phoneNumberHintIntentResultLauncher.launch(result.intentSender.sendIntent)
} catch (e: Exception) {
Log.e(TAG, "Launching the PendingIntent failed")
} as OnSuccessListener<in PendingIntent>
}
.addOnFailureListener(
Log.e(TAG, "Phone Number Hint failed")
)
I am building an android app in MVVM architecture using Firebase. I am trying to do User's password change and whenever i start my code, application freezes or just stops responding. I spent a lot of time to search what is wrong with it and yet no fix. If anyone know why it behave like this I would appreciate your help. My code:
Function called in fragment:
private fun startChangePasswordDialog(){
val dialogView = LayoutInflater.from(activity).inflate(R.layout.dialog_change_password, null)
val builder = AlertDialog.Builder(activity).setView(dialogView)
val dialog: AlertDialog = builder.show()
val changePassword = dialogView.findViewById<Button>(R.id.changePasswordBT)
val cancel = dialogView.findViewById<Button>(R.id.changePasswordCancelBT)
val passwordET = dialogView.findViewById<EditText>(R.id.changePasswordET)
changePassword?.setOnClickListener {
val newPassword = passwordET.text.trim().toString()
if (TextUtils.isEmpty(newPassword) || newPassword.length < viewModel.PASSWORD_MIN_VALUE){
Toast.makeText(requireContext(), R.string.password_too_short, Toast.LENGTH_SHORT).show()
}
else{
viewModel.changeUsersPassword(newPassword)
viewModel.needUserAuthentication.observe(requireActivity(), {
if (it == true) reAuthenticateUser()
})
}
dialog.dismiss()
}
cancel?.setOnClickListener {
dialog.dismiss()
}
ViewModel function:
fun changeUsersPassword(password: String) {
Log.d(TAG,"Starting user's password change procedure")
when (repository.changeUserPassword(password)){
PasswordChangeCallbackEnum.FACEBOOK_USER -> {
_toastMessage.value = R.string.facebook_user_password_change
Log.d(TAG, "User's password will not be changed, logged in as Facebook user")
}
PasswordChangeCallbackEnum.PASSWORD_CHANGE_ERROR -> {
_toastMessage.value = R.string.password_change_error
Log.d(TAG, "Error while changing user's password")
}
PasswordChangeCallbackEnum.PASSWORD_CHANGED -> {
_toastMessage.value = R.string.password_change_success
Log.d(TAG, "User's password changed successfully")
}
PasswordChangeCallbackEnum.NEED_USER_AUTHENTICATION -> {
_needUserAuthentication.value = true
}
}
}
Firebase Repository (I have changed it several times when tried to fix this):
fun changeUserPassword(password: String): PasswordChangeCallbackEnum {
var result = PasswordChangeCallbackEnum.PASSWORD_CHANGE_ERROR
if (currentUser != null) {
for (userInfo in currentUser.providerData) {
if (userInfo.providerId == "facebook.com") {
Log.d(TAG, "Cannot change password for user logged in with facebook")
result = PasswordChangeCallbackEnum.FACEBOOK_USER
}
}
}
try{
val updateTask = authentication.currentUser?.updatePassword(password)
updateTask?.addOnSuccessListener {
Log.d(TAG, "User's password change state: SUCCESS")
result = PasswordChangeCallbackEnum.PASSWORD_CHANGED
}
}catch (exception: FirebaseAuthRecentLoginRequiredException){
Log.d(TAG, "Need user to authenticate again")
result = PasswordChangeCallbackEnum.NEED_USER_AUTHENTICATION
}
return result
}
The problem is, you are doing task in ui thread.
Use coroutines for the task to do in worker thread .
you can have more information about coroutines. here
You can also use RxJava for it or some Async task.
It will prevent the ui freezing
I am using Csipsimple for my Voip app. when i am click logout button the login screen comes but when i am call after logout on this number the incoming call is coming and call has been connected.
fun disconnect(quit: Boolean, ctx: Context?) {
try {
val intent = Intent(SipManager.ACTION_OUTGOING_UNREGISTER)
intent.putExtra(SipManager.EXTRA_OUTGOING_ACTIVITY, ComponentName(ctx, MainActivity::class.java))
ctx!!.sendBroadcast(intent)
val pref = PrefManager(ctx)
pref.setLoggedIn(false)
val crMain = ChattingClass()
crMain.logoutFromChat(this)
if (quit) {
// also delete the shared preference when disconnect
deleteUserFromPref(ctx)
val finish = Intent(ctx, LoginMainActivity::class.java)
finish.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
finish.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
(ctx as Activity).startActivity(finish)
(ctx as Activity).finish()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
I am call this disconnect method on click of logout button. i am unregister the sip connection and clear a shared preference.
After Some Research and Changes a little bit code in my prefProviderWrapper class, i am getting the perfect solution for CsipSimple Account logout.
private var prefProviderWrapper: PreferencesProviderWrapper? = null
fun disconnect(quit: Boolean, ctx: Context?) {
try {
prefProviderWrapper = PreferencesProviderWrapper(ctx)
prefProviderWrapper!!.setPreferenceBooleanValue(PreferencesWrapper.HAS_BEEN_QUIT, true)
val intent = Intent(SipManager.ACTION_OUTGOING_UNREGISTER)
intent.putExtra(SipManager.EXTRA_OUTGOING_ACTIVITY, ComponentName(ctx, MainActivity::class.java))
ctx!!.sendBroadcast(intent)
val pref = PrefManager(ctx)
pref.setLoggedIn(false)
val crMain = ChattingClass()
crMain.logoutFromChat(this)
if (quit) {
// also delete the shared preference when disconnect
deleteUserFromPref(ctx)
val finish = Intent(ctx, LoginMainActivity::class.java)
finish.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK
finish.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
(ctx as Activity).startActivity(finish)
(ctx as Activity).finish()
}
} catch (e: Exception) {
e.printStackTrace()
}