I am justing trying to get phone number using GetPhoneNumberHintIntentRequest to replace HintRequest.
So just trying to follow google developer doc https://developers.google.com/identity/phone-number-hint/android#kotlin_2. But after following doc I feel this doc is incomplete.
val phoneNumberHintIntentResultLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
try {
val phoneNumber = Identity.getSignInClient(requireActivity()).getPhoneNumberFromIntent(result.data)
} catch(e: Exception) {
}
}
So as per doc you need to pass intent to phoneNumberHintIntentResultLauncher but there is no method inside GetPhoneNumberHintIntentRequest.
Even if you see doc then you realise that you need to replace signInClient to getSignInClient.
If any one know about above issue then let me know or any doc where I can achieve my goal.
Have been facing this recently.
Please change the result launcher type as follows.
val resultLauncher: ActivityResultLauncher<IntentSenderRequest> = registerForActivityResult(StartIntentSenderForResult()) { result ->
try {
val phoneNumber = Identity.getSignInClient(requireActivity()).getPhoneNumberFromIntent(result.data)
// Do something with the number
} catch (e: Exception) {
Log.e(TAG, "Phone Number Hint failed")
}
And launch the intent as
...
.addOnSuccessListener { request: PendingIntent ->
try {
resultLauncher.launch(IntentSenderRequest.Builder(request).build())
} catch(e: Exception) {
Log.e(TAG, "Launching the PendingIntent failed")
}
}
...
The document is indeed incomplete as it seems.
// initialise above onCreate
private ActivityResultLauncher<IntentSenderRequest> someActivityResultLauncher;
// declare in onCreate
private void phoneSelection() {
GetPhoneNumberHintIntentRequest request = GetPhoneNumberHintIntentRequest.builder().build();
Identity.getSignInClient(RegistrationActivity.this)
.getPhoneNumberHintIntent(request)
.addOnFailureListener(e -> {
Toast.makeText(activity, "Error : "+e.getMessage(), Toast.LENGTH_SHORT).show();
}).addOnSuccessListener(pendingIntent -> {
IntentSenderRequest intentSenderRequest = new IntentSenderRequest.Builder(pendingIntent.getIntentSender()).build();
someActivityResultLauncher.launch(intentSenderRequest);
});
}
// declare in onCreate
private void resultLauncher() {
someActivityResultLauncher = registerForActivityResult(new ActivityResultContracts.StartIntentSenderForResult(), result -> {
try {
String phoneNumber = Identity.getSignInClient(RegistrationActivity.this).getPhoneNumberFromIntent(result.getData());
binding.editNumber.setText(phoneNumber.substring(3)); //get the selected phone
} catch (ApiException e) {
e.printStackTrace();
Toast.makeText(activity, "Error : "+ e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
Related
i am investigating Google Identity Services in my current Android project for Sign In With Google.
theres this code in the docs:-
private static final int REQUEST_CODE_GOOGLE_SIGN_IN = 1; /* unique request id */
private void signIn() {
GetSignInIntentRequest request =
GetSignInIntentRequest.builder()
.setServerClientId(getString(R.string.server_client_id))
.build();
Identity.getSignInClient(activity)
.getSignInIntent(request)
.addOnSuccessListener(
result -> {
try {
startIntentSenderForResult(
result.getIntentSender(),
REQUEST_CODE_GOOGLE_SIGN_IN,
/* fillInIntent= */ null,
/* flagsMask= */ 0,
/* flagsValue= */ 0,
/* extraFlags= */ 0,
/* options= */ null);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Google Sign-in failed");
}
})
.addOnFailureListener(
e -> {
Log.e(TAG, "Google Sign-in failed", e);
});
}
however startIntentSenderForResult method is marked ad deprecated with the following comment:-
This method has been deprecated in favour of using the Activity Result API which brings increased type
safety via an ActivityResultContract and the prebuilt contracts for common intents available in
androidx.activity.result.contract.ActivityResultContracts, provides hooks for testing, and allow
receiving results in separate, testable classes independent from your activity.
Use registerForActivityResult(ActivityResultContract, ActivityResultCallback) passing
in a StartIntentSenderForResult object for the ActivityResultContract.
i do not understand how to replace startIntentSenderForResult with registerForActivityResult(ActivityResultContract, ActivityResultCallback), when i follow the instructions and pass the StartIntentSenderForResult object for the ActivityResultContract as follows i get a compile error message
heres my code
private fun signIn() {
val request: GetSignInIntentRequest = GetSignInIntentRequest.builder()
.setServerClientId(getString(R.string.server_client_id))
.build()
Identity.getSignInClient(this#MainActivity)
.getSignInIntent(request)
.addOnSuccessListener {
registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) {
Log.d(TAG, "signIn() called ${it.data}")
Log.d(TAG, "signIn() called ${it.resultCode}")
}
}
.addOnFailureListener { e -> Log.e(TAG, "Google Sign-in failed", e) }
}
this is what i ended up with:-
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initializeGoogleSignIn()
}
private val launcher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult(), ::handleSignInResult)
private fun handleSignInResult(result: ActivityResult) {
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(result.data)
try {
val account = task.getResult(ApiException::class.java)
Log.d(TAG, "handleSignInResult() called with: result = $account")
} catch (ex: ApiException) {
Log.e(TAG, "handleSignInResult: ", ex)
}
}
private fun initializeGoogleSignIn() {
val request = GetSignInIntentRequest.builder()
.setServerClientId(getString(R.string.server_client_id))
.build()
Identity.getSignInClient(this)
.getSignInIntent(request)
.addOnSuccessListener { result ->
val intentSenderRequest = IntentSenderRequest.Builder(result).build()
launcher.launch(intentSenderRequest)
}
.addOnFailureListener { e ->
Log.e(TAG, "initializeGoogleSignIn: ",e )
}
}
}
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 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) }
}
I have a method that looks like that:
private lateinit var cards: List<Card>
fun start() = viewModelScope.launch {
if (!::cards.isInitialized) {
getCards().collect { result ->
result
.doIfSuccess {
cards = it.data
Log.d(TAG, "Received cards")
}
.doIfError {
_errorState.setIfNotEqual(it.exception)
Log.e(TAG, "Cards were not received because of ${it.exception}")
return#collect // <--- that's the place
}
}
}
Log.d(TAG, "Message that needs to be shown only if cards were received")
if (сards.isEmpty()) {
Log.e(TAG, "Сards list is empty")
_errorState.setIfNotEqual(NoCardsException)
return#launch
}
val сard = сards[0]
}
I need to completely return from the method, not only from the .collect block, I've tried to use return#launch or some other custom labels, but it doesn't work even though Kotlin compiler suggests me to set it like that:
I think you can use transformWhile to create a new Flow that does an operation on each item you receive until you return false. Then collect that Flow. I didn't test this because I'm not really sure of how you've structured .doIfSuccess and .doIfError.
fun start() = viewModelScope.launch {
if (!::cards.isInitialized) {
getCards().transformWhile { result ->
result
.doIfSuccess {
cards = it.data
Log.d(TAG, "Received cards")
}
.doIfError {
_errorState.setIfNotEqual(it.exception)
Log.e(TAG, "Cards were not received because of ${it.exception}")
return#transformWhile false
}
return#transformWhile true
}.collect()
}
//...
}
EDIT:
If you only want the first value from the Flow, you could do this:
fun start() = viewModelScope.launch {
if (!::cards.isInitialized) {
getCards().first()
.doIfSuccess {
cards = it.data
Log.d(TAG, "Received cards")
}
.doIfError {
_errorState.setIfNotEqual(it.exception)
Log.e(TAG, "Cards were not received because of ${it.exception}")
return#launch
}
}
//...
}
Razorpay callbacks is not working in fragment instead of activity using fragment please give a solution If anyone aware thanks in advance.
private fun startPayment() {
val activity: Activity = requireActivity()
val co = Checkout()
try {
val options = JSONObject()
options.put("name", "Vendor")
options.put("description", " for Order")
//You can omit the image option to fetch the image from dashboard
options.put("image", "https://rzp-mobile.s3.amazonaws.com/images/rzp.png")
options.put("currency", "INR")
val payment: String = "1"//getcart?.CartTotal.toString()
// amount is in paise so please multiple it by 100
//Payment failed Invalid amount (should be passed in integer paise. Minimum value is 100 paise, i.e. ₹ 1)
var total = payment.toDouble()
total = total * 100
options.put("amount", total)
val preFill = JSONObject()
preFill.put("email", "hell#gmail.com")
preFill.put("contact", "9898989898")
options.put("prefill", preFill)
co.open(requireActivity(), options)
} catch (e: Exception) {
Toast.makeText(activity, "Error in payment: " + e.message, Toast.LENGTH_SHORT).show()
e.printStackTrace()
}
}
override fun onPaymentSuccess(s: String?) {
toast("onPaymentSuccess")
Log.i(TAG, "onPaymentSuccess: $s")
}
override fun onPaymentError(i: Int, s: String?) {
Log.e(TAG, "error code "+i.toString()+" -- Payment failed "+s.toString())
try {
toast("Payment error please try again")
} catch (e : Exception) {
Log.e("OnPaymentError", "Exception in onPaymentError", e);
}
}
Amount should be in Integer and in paise.
implement result listener to the fragment host activity and override error and success function there.
in fragment you won't get Razorpay callback function, so you should implement PaymentResultListener or PaymentResultWithDataListener in activity and from activity you have call your fragment and do your api call for razor pay response.
in your Activity:
#Override
public void onPaymentSuccess(String s, PaymentData paymentData) {
try {
FeeFragment feeList = (FeeFragment) mViewPager.getAdapter().instantiateItem(mViewPager, mViewPager.getCurrentItem());
feeList.checkRazorResponse(paymentData, true);
} catch (Exception e) {
Log.e("Exception in success", e.toString());
e.printStackTrace();
}
}
in your Fragment:
public void checkRazorResponse(PaymentData paymentData, boolean success) {
if (success) {
updatePaymentStatus(paymentData);
//do your api call
} else {
//handle error message
}
}
Razorpay payment integration is not supported on the fragment. You have to implement it on Activity.
Like this way
This code is for fragment:
binding.tvPlaceOrder.setOnClickListener(view -> {
startActivity(new Intent(getActivity(), PaymentActivity.class));
}
}
});
This code is for Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPaymentBinding.inflate(layoutInflater)
setContentView(binding.root)
payOnline()
}
private fun payOnline() {
val checkout = Checkout()
checkout.setKeyID(getString(R.string.razorpay_api_key))
checkout.setImage(R.mipmap.ic_launcher)
try {
val options = JSONObject()
options.put("name", "mName")
options.put("currency", "INR")
options.put("image", R.mipmap.ic_launcher)
options.put("amount", 10000) //pass amount in currency subunits
options.put("prefill.email", "roydeveloper01#gmail.com")
options.put("prefill.contact", "8620828385")
checkout.open(this, options)
} catch (e: Exception) {
Toast.makeText(this, "Error in starting Razorpay Checkout: $e", Toast.LENGTH_LONG).show()
}
}
override fun onPaymentSuccess(p0: String?) {
try {
binding.tvId.text = "Payment Successful \n Transaction ID $p0"
} catch (e: NoSuchAlgorithmException) {
binding.tvId.text ="Exception"
}
}
override fun onPaymentError(p0: Int, p1: String?) {
try {
binding.tvId.text ="Exception: $p1"
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
binding.tvId.text ="Error: $p1"
}
My problem is solved this way. I think your problem will also solve . Best of luck.