I'm trying to use google Place Autocomplete in my app.
Like described in the documentation, there is two ways to use this feature : one using a fragment and the other way is to use an Intent and that's what I choose.
My code is like below
Gradle:
implementation 'com.google.android.libraries.places:places:2.5.0'
Kotlin:
Part 1
btn.setOnClickListener {
if (!Places.isInitialized()) {
Places.initialize(
requireActivity().applicationContext,
getString(R.string.google_maps_key)
)
}
#Suppress("DEPRECATION")
startActivityForResult(
Autocomplete
.IntentBuilder(
AutocompleteActivityMode.OVERLAY,
listOf(
Place.Field.ID,
Place.Field.NAME,
Place.Field.LAT_LNG,
Place.Field.ADDRESS,
Place.Field.ADDRESS_COMPONENTS
)
).build(requireContext()),
AUTOCOMPLETE_REQUEST_CODE
)
}
Part 2
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
when (resultCode) {
Activity.RESULT_OK -> {
data?.let {
val place = Autocomplete.getPlaceFromIntent(data)
Timber.i(TAG, "Place: ${place.name}, ${place.id}")
}
}
AutocompleteActivity.RESULT_ERROR -> {
// TODO: Handle the error.
data?.let {
val status = Autocomplete.getStatusFromIntent(data)
Timber.i(TAG, status.statusMessage)
}
}
Activity.RESULT_CANCELED -> {
// The user canceled the operation.
}
}
return
}
super.onActivityResult(requestCode, resultCode, data)
}
The overlay 'Place Auto Complete' view appear perfectly but when I try to tape in the keyboard to search for some place, the view crashes not the app. only the view and I got the error below (I don't know if it is related) :
set_timerslack_ns write failed: Operation not permitted
Any idea how to solve this ?
Did you "enable" your api key for using the google places?
Related
I was recently updating deprecated methods in my App and there is one that I have a few questions about. Did not find any example or explanation describing my use case...
There is a local backup and a restore functions. User has to choose a directory either where to save data to or to restore data from. It was implemented like this:
binding.backupBtn.setOnClikListener{
openDirectory(LOCAL_BACKUP_CODE)
}
binding.restoreBtn.setOnClickListener{
openDirectory(LOCAL_RESTORE_CODE)
}
private fun openDirectory(requestCode: Int){
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
startActivityForResult(intent, requestCode)
}
And then depending on the request code backup or restore:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode = Activity.RESULT_OK) {
val uriTree = data?.data ?: return
if (requestCode == LOCAL_BACKUP_CODE) {
localBackup(uriTree)
}
if (requestCode == LOCAL_RESTORE_CODE) {
localRestore(uriTree)
}
}
}
Now with this Activity Result Contracts how can I specify, and is it possible at all, custom request code. Android documentation for accessing a directory still uses startActivityForResult()
Link
ActivityResultContract.StartActivityForResult() - is a generic contract that takes any Intent but there is no way to provide custom request code.
As for now I simply created 2 launchers for backup and restore:
val backupRequest = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()){
if (it != null){
localBackup(it)
}
}
val restoreRequest = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()){
if (it != null){
localRestore(it)
}
}
binding.backupBtn.setOnClickListener {
backupRequest.launch(null)
}
binding.restoreBtn.setOnClickListener {
restoreRequest.launch(null)
}
Is it the way to do it? I looked into custom Contracts, but can't figure out how I can return Uri AND custom variable (request code in this case).
I am trying to learn Kotlin and I'm building a simple example as I go. I have 3 image buttons that open the camera and take a photo. The thumbnail is then set into an ImageView. I've used the examples from https://developer.android.com/training/camera/photobasics?hl=en to get the basics working (figuring if I can make it work for one, it'll work for all. It does indeed work for one, but I can't figure out how to make it one function that drops the thumbnail into the correct ImageView.
Inside my onCreate I have the listener for each of the buttons that will invoke the camera:
camRead1.setOnClickListener {dispatchTakePictureIntent() }
camRead2.setOnClickListener {dispatchTakePictureIntent() }
camRead3.setOnClickListener {dispatchTakePictureIntent() }
And I took the sample from the url above:
val REQUEST_IMAGE_CAPTURE = 1
private fun dispatchTakePictureIntent() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val thumb: ImageView = findViewById(R.id.thumbRead1)
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
val imageBitmap = data.extras.get("data") as Bitmap
thumb.setImageBitmap(imageBitmap)
}
}
and pasted it into my class MainActivity, and after I replaced imageView in the override function with a variable (thumb) and added the super, it worked perfectly for the first one.
However, I am trying to get 3 photos, read1, read2, and read3 which each need to display the thumb in thumbRead1, thumbRead2 and thumbRead3. I can't figure out how the onActivityResult is executed since the call inside dispatchTakePictureIntent is calling startActivityForResult (especially as Android Studio says that startActivityForResult is deprecated).
Obviously, once onActivityResult executes, I can see that thumb defines R.id.thumbRead1 and receives imageBitmap but I don't understand how I can make it aware of the button that was clicked.
Without understanding how onActivityResult is called, I'm thinking that if I can do something like:
findViewById(R.id("thumbRead" + imgID))
to define the specific ImageView that I want the photo pasted into. Am I on the right track here? If not, what is the recommended way of doing this?
Note they've recently added what's supposed to be a cleaner way of starting other activities for results and getting the results, explained here. But since you're already doing it the traditional way, I'll explain how to get that working.
I think the easiest thing to do in this situation is just make more request codes, so you can check which request it was.
val REQUEST_IMAGE_CAPTURE_SOURCE_1 = 1
val REQUEST_IMAGE_CAPTURE_SOURCE_2 = 2
val REQUEST_IMAGE_CAPTURE_SOURCE_3 = 3
//...
camRead1.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_1) }
camRead2.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_2) }
camRead3.setOnClickListener { dispatchTakePictureIntent(REQUEST_IMAGE_CAPTURE_SOURCE_3) }
//...
private fun dispatchTakePictureIntent(requestCode: Int) {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, requestCode)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode != RESULT_OK) {
// possibly show message to user
return
}
val imageViewId = when (requestCode) {
REQUEST_IMAGE_CAPTURE_SOURCE_1 -> R.id.thumbRead1
REQUEST_IMAGE_CAPTURE_SOURCE_2 -> R.id.thumbRead2
REQUEST_IMAGE_CAPTURE_SOURCE_3 -> R.id.thumbRead3
}
val imageView = findViewById<ImageView>(imageViewId)
imageView.imageBitmap = data.extras.get("data") as Bitmap
}
By the way, if you want to get an ID for a view using the String like you were showing you were trying, you would do it like this:
val viewId = resources.getIdentifier("thumbRead$imgId", "id", packageName)
val imageView = findViewById<ImageView>(viewId)
You need to pass different request code for each call and pass it to the dispatchTakePictureIntent function. You do not need to get id by findviewbyid. You simply can add the image on the basis of the request code.
val REQUEST_IMAGE_CAPTURE_ONE = 1
val REQUEST_IMAGE_CAPTURE_TWO = 2
val REQUEST_IMAGE_CAPTURE_THREE = 3
private fun dispatchTakePictureIntent(requestCode: Int) {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
startActivityForResult(takePictureIntent, requestCode)
} catch (e: ActivityNotFoundException) {
// display error state to the user
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
val imageBitmap = data.extras.get("data") as Bitmap
if (requestCode == REQUEST_IMAGE_CAPTURE_ONE ) {
thumbRead1.setImageBitmap(imageBitmap)
}else if (requestCode == REQUEST_IMAGE_CAPTURE_TWO ) {
thumbRead2.setImageBitmap(imageBitmap)
}else if (requestCode == REQUEST_IMAGE_CAPTURE_THREE ) {
thumbRead3.setImageBitmap(imageBitmap)
}
}
}
I'm using Kotlin. I have beent trying to choose a folder to create a file in it and export Data from my Database into said file. But now it showed me, that startActivityForResult is deprecated
I have read the Question:
OnActivityResult method is deprecated, what is the alternative?
, but sadly, I couldn't see how you would implement that in a Optionsmenu, to open a Action_Create_Document for a Data-Export.
As a non-native Speaker, i also had quite a bit of trouble to understand the basic training: https://developer.android.com/training/basics/intents/result .
So my question is: How do you implement a call to choose a location and create a txt-file and the take said filelocation to fill it with text, with the registerForActivityResult without moving to another Activity/with staying on the Activity you are.
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.Export -> {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "text/plain"
intent.putExtra(Intent.EXTRA_TITLE, "Spells.txt")
startActivityForResult(intent, 112)
return true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
super.onActivityResult(requestCode, resultCode, resultData)
if (requestCode == 112 && resultCode == RESULT_OK) {
Toast.makeText(this, "Created", Toast.LENGTH_LONG).show()
val path = resultData?.data?.path
val myfile: File
if (path != null) {
myfile = File(path)
....
doing stuff()
}
}
}
I have found the Problem in my thinking. I just had to use the Intent I created before to launch the resultLauncher, that was shown on the previous question, instead of the Activity-changing Intent.
Also, I found, that the Value val resultLauncher, that was shown, had to be declared inside the class but outside the other functions, which was the part, where I got confused. Guess I got routine-blinded and should take more Breaks
Here some code about how you can use the new registerForActivityResult approach, in this case It replaces the Intent.ACTION_CREATE_DOCUMENT intent.
class YourActivity {
// This is the launcher ...
// CreateDocument() -> Intent.ACTION_CREATE_DOCUMENT
private val getCreateFileUriContent = registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri: Uri? ->
// Handle the returned Uri
uri?.let { onCreateFileSelected(it) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//....
someButton.setOnClickListener {
//launch for results
getCreateFileUriContent.launch("test.json")
}
}
}
I am trying to implement the Firebase AuthUI for a dummy app following the course by google itself on udacity. I am not getting the same output as in the course itself and idk what to do exactly or what is going wrong. Below is the code i have written to start up the AuthUI:
private fun launchSignInFlow() {
val providers =
arrayListOf(
AuthUI.IdpConfig.EmailBuilder().build(),
AuthUI.IdpConfig.GoogleBuilder().build()
)
startActivityForResult(
AuthUI.getInstance().createSignInIntentBuilder().setAvailableProviders(
providers
).build(), SIGN_IN_RESULT_CODE
)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == SIGN_IN_RESULT_CODE) {
val response = IdpResponse.fromResultIntent(data)
if (resultCode == Activity.RESULT_OK) {
Log.i(
TAG,
"Successfully signed in user " +
"${FirebaseAuth.getInstance().currentUser?.displayName}!"
)
} else {
Log.i(TAG, "Sign in unsuccessful ${response?.error?.errorCode}")
}
}
}
this is the output screen/ui that i get from this code
And this is what the output should be like according to the course i am following
What's worse is that even when i try to enter an email to the output i get, the screen gets stuck and does nothing at all. This is the link for the video of google for this specific task
https://youtu.be/JKZpZvbm3Bk
I was developing an app and tested it on Android 9 and all was good.
One week ago I updated my phone to Android 10 and noticed that the app that I develop start working in the wrong way. I checked again on Android 9 and it's ok, but new Android 10 is not working as expected.
The problem related with location:
I ask location permission (using Dexter)
Dexter.withActivity(this).withPermission(Manifest.permission.ACCESS_FINE_LOCATION).withListener(object : PermissionListener {
#SuppressLint("MissingPermission")
override fun onPermissionGranted(response: PermissionGrantedResponse?) {
Timber.d("onPermissionGranted [%s]", response?.permissionName)
turnOnLocation(OnSuccessListener {
requestLocation()
})
}
override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest?, token: PermissionToken?) {
Timber.d("onPermissionRationaleShouldBeShown")
token?.continuePermissionRequest()
}
override fun onPermissionDenied(response: PermissionDeniedResponse?) {
Timber.d("onPermissionDenied [%s]", response?.permissionName)
}
}).check()
When permission is granted I tried turn on location
private fun turnOnLocation(onSuccessListener: OnSuccessListener<LocationSettingsResponse>? = null) {
val builder = LocationSettingsRequest.Builder().addLocationRequest(locationRequest).setAlwaysShow(true)
val locationSettings = settingsClient.checkLocationSettings(builder.build())
onSuccessListener?.let { locationSettings.addOnSuccessListener(it) }
locationSettings.addOnFailureListener {
if (it is ResolvableApiException) it.startResolutionForResult(this#MainActivity, requestCheckSettings)
}
}
Then I wait for activity result here:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == requestCheckSettings) {
if (resultCode == RESULT_OK) {
Timber.i("GPS enabled")
requestLocation()
} else {
Timber.e("GPS is not enabled")
}
}
}
Finally:
Blockquote
In ANDROID 10:
After click on "OK" in "Turn On location" dialog - app navigate me to unexpected behavior
Timber.e("GPS is not enabled")
Blockquote
In ANDROID 9:
After click on "OK" in "Turn On location" dialog - app navigate me to the expected behavior
Timber.i("GPS enabled")
Does anyone have thoughts about this?