My android app needs some permissions, so I used the following code according to the developer's Guide.But it went wrong.
ActivityResultLauncher launcher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), result -> {
if(result){
Log.d(TAG, "onActivityResult: Permission Granted");
}
else{
Log.d(TAG, "onActivityResult: No Permission");
}
});
launcher.launch(Manifest.permission.ACCESS_FINE_LOCATION);
Exception:
Caused by: java.lang.IllegalArgumentException: Can only use lower 16 bits for requestCode
Why is the "recommended" method wrong?
The problem is not in THIS code. RequestCode is valid from 0 up to 32766 but when your code (or a 3rd library) calls "...requestPermissions(.., .., requestCode)" (maybe in your "launch(...)" method) the "requestCode" goes outside that range.
Related
I'm currently attempting to write a view in an android app that will open a camera on a button press, let the user record a video, and stash the URI in a member attached to said view. I'm very hopeful this is possible, but unsure because I can't find many docs regarding the issue.
I'm using the top answer here as a reference for capturing the URI, and it's very comprehensive, but not working in my case for reasons of which I am unsure.
I declare my variable at the top of the file as so
private var videoUri: Uri? = null
The rest of the relevant code happens here:
val recordVideoResult = registerForActivityResult(ActivityResultContracts.CaptureVideo()) { uri: Uri? ->
uri?.let {
this.videoUri = uri
}
}
val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
launchCamera()
} else {
Toast.makeText(this, "Can't open camera because permission is denied. Please provide access in settings.", Toast.LENGTH_SHORT).show()
}
}
fun launchCamera() {
if (packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) { // First check if camera is available in the device
when {
ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> {
recordVideoResult.launch(this.uri)
}
else -> {
// You can directly ask for the permission.
// The registered ActivityResultCallback gets the result of this request.
requestPermissionLauncher.launch(
Manifest.permission.CAMERA
)
}
}
}
}
My IDE and compiler yell at me with the below error, which looks like a bug to me, but will not go away.
I'm very unsure what I'm doing wrong. Forgive me if it's incredibly obvious, I've been writing Kotlin for less than a week.
You've got the input and output of CaptureVideo mixed up. The CaptureVideo contract says:
An ActivityResultContract to take a video saving it into the provided content-Uri.
Returns true if the video was saved into the given Uri.
So the input is a Uri - that's what you need to pass to launch. The output is a Boolean. This can be confirmed by looking at the class itself, which shows the complete type - ActivityResultContract<Uri, Boolean>.
This means what you actually need to do is:
Setup a FileProvider. This is how you generate a Uri from a File that your app owns that is suitable to send to the launch of a CaptureVideo Intent. You're the one who picks where the video is stored, not the camera app.
Generate the appropriate File associated with where you want to save your video and store it as a variable in your class like you were previously doing with your videoUri, e.g., in a variable named file (as per the note on the Launching an Intent documentation, you'll probably also want to store that in onSaveInstanceState() in case your process is destroyed while the camera is up).
Use the FileProvider APIs to generate a Uri from your File and pass that to your call to launch.
val contentUri = FileProvider.getUriForFile(
this, // your Activity or
"com.example.myapp.fileprovider", // The android:authorities value from your manifest
file) // The File you want to store the video into
recordVideoResult.launch(contentUri)
Change your call to registerForActivityResult to account for the success Boolean result:
val recordVideoResult = registerForActivityResult(ActivityResultContracts.CaptureVideo()) { success ->
if (success) {
// Now your file contains the fully captured video
} else {
// The user cancelled taking a video
}
}
I get
java.lang.IllegalArgumentException: No suitable parent found from the given view. Please provide a valid view.
at com.google.android.material.snackbar.Snackbar.makeInternal(Snackbar.java:198)
at com.google.android.material.snackbar.Snackbar.make(Snackbar.java:157)
ActivityResultLauncher<Intent> mLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(final ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
final Intent data = result.getData();
Snackbar.make(MainFragment.this.binding.getRoot(), data.getStringExtra("nextEvent"), Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
}
});
I know you think "not again..." But why do I get this problem neither in the emulator nor on my samsung devices. This ERROR happens only on one XIAOMI with MIUI 12 (Android 10).
My target SDK is 26.
Anyone faced something like this?
Could figure it out...
"Don't keep activities" was enabled in the developer settings.
Maybe the deprecated startActivityForResult will work with this setting enabled.
I want to make google sign in to my app, but I get this error.
startActivityForResult() deprecated in java
This is my code:
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent,RC_SIGN_IN)
And I know, I must use registerForActivityResult(); but I don't know how to use it.
The code linked on Drive is close, but not quite correct. You have mixed up the resultCode and responseCode. You should check result.resultCode == Activity.RESULT_OK not result.resultCode == 100 in your callback for registerForActivityResult.
With the old startActivityForResult(intent,code) flow you would launch the activity with an integer code (e.g. 100), then check for that code in onActivityResult to make sure you were handling the right response. With the callbacks that integer request/response code is no longer necessary or used.
private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->
if (result.resultCode == Activity.RESULT_OK) {
// handle the response in result.data
}
}
then you use it as others have indicated
val signInIntent = googleSignInClient.signInIntent
launcher.launch(signInIntent)
There are also some examples of this on the answers here
It's not an error for now. It's warning about deprecated method. registerForActivityResult() reuired ActivityResultContract. In this case it's StartActivityForResult(). All you need is declare a variable
private val launcher = registerForActivityResult(StartActivityForResult()){result -> //Intent
....
}
and launch intent when needed with launcher.launch(signInIntent)
It's a warning. However it leaves you feeling weird and worrying about future versions.
So I did it this way.
val signInIntent: Intent = mGoogleSignInClient.signInIntent
launcher.launch(signInIntent)
The important thing here is to source the data that uses the google intent thingi.
private val launcher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->
if (result.resultCode == Activity.RESULT_OK) {
val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
handleSignInResult(task)
}
}
So that's it. It works and no warning.
I also made a question and it's a mystery, so it would be great if you check it out.
Cannot generate app bundle... something with mergeReleaseResources
I am getting the following error:
java.lang.IllegalStateException: Cannot use sign-in mode: SIGN_IN_MODE_OPTIONAL. Mode was already set to SIGN_IN_MODE_NONE
What does this mean? How to prevent it?
The suggestion in other similar SO question was
mGoogleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL);
But I have been using this itself.
Here is the onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_OAUTH) {
authInProgress = false;
if (resultCode == RESULT_OK) {
progressDialog.dismiss();
if (!googleApiClient.isConnecting() && !googleApiClient.isConnected()) {
googleApiClient.connect(GoogleApiClient.SIGN_IN_MODE_OPTIONAL);
} else {
onConnected(null);
}
} else if (resultCode == RESULT_CANCELED) {
progressDialog.dismiss();
startApiClientConnect();
}
} else {
progressDialog.dismiss();
startApiClientConnect();
}
}
After the initial connection attempt if it was not successful then the googleApiClient.connect is reattempted in the onActivityResult. I believe this is reattempt is causing the problem. After initial connection failure / some user action makes the SIGN_IN_MODE_NONE.
How to handle this?
It looks like you're not allowed to provide a sign in mode to the connect(int) method more than once. The documentation says "It is an error to make multiple calls to this method passing different modes. Once a mode is selected, all future connect calls must use the same mode." So it might be that you're calling connect() with differing arguments. SIGN_IN_MODE_NONE doesn't seems to be an option for the parameter, so I think you're calling connect() in one case and connect(int) in another (with SIGN_IN_MODE_OPTIONAL). Check that out and see if you can make them consistent.
Also, I believe callbacks for GoogleApiClient are onConnected(Bundle) and onConnectionFailed(ConnectionResult)
I am trying to integrate BrainTree into my app, but I'm having some issues with startActivityForResult() and onActivityResult(). I have already properly retrieved a clientToken but for some reason I'm always receiving a resultCode of 2 in onActivityResult. In addition I also get this in my Logs:
I/art: Rejecting re-init on previously-failed class
java.lang.Class
Any idea what's going on? Here's some snippets of my code in case it helps:
This is the onClick method in my fragment.
void onPaymentClick() {
PaymentRequest paymentRequest = new PaymentRequest().clientToken("<client_token>");
getActivity().startActivityForResult(paymentRequest.getIntent(storeOrderActivity), 1);
}
}
And this is the onActivityResult code in my activity. (PostOrder is the the function that's supposed to run once Braintree sends a nonce back to me, but this doesn't even run since I get a resultCode of 2)
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
if (resultCode == Activity.RESULT_OK) {
PaymentMethodNonce paymentMethodNonce = data.getParcelableExtra(
BraintreePaymentActivity.EXTRA_PAYMENT_METHOD_NONCE
);
PostOrder.postOrder(this, fabCartAdapter.getCart(), paymentMethodNonce.getNonce());
}
}
}
The resultCode==2 is reserved for BRAINTREE_RESULT_DEVELOPER_ERROR:
The payment method flow halted due to a resolvable error (authentication, authorization, SDK upgrade required). The reason for the error will be returned in a future release.
Probably you need to double check if the SDK is set it up correctly.