I am building barcode scanning functionality into an app, and have followed this guide: https://learntodroid.com/how-to-create-a-qr-code-scanner-app-in-android/.
I have a main activity, which launches my QR scanning activity. When I detect a particular uri from the QR code (based on scheme, host and path), I want to end the QR scanning activity, return to my main activity and launch a dialog.
This is all working - the first time. However, if I relaunch the scanning activity, it no longer detects QR codes, and my onQRCodeFound never gets hit. (Killing and restarting the app resets it, I can scan 1 QR code successfully again, but then it stops detecting them if I reopen the QR activity). The image preview is shown, but the QR never gets recognised.
I do get W/System.err: com.google.zxing.NotFoundException printed to the log repeatedly while the activity is open.
UPDATE
On more investigation I found that on the 2nd (and subsequent times) I launch this activity the previewView has a width and height of 0 (the first time, it's correctly getting the size of 1080x2280). Setting a target resolution of 0x0 for the ImageAnalysis was the problem.
If I hard code the resolution, rather than using previewView.getWidth() and previewView.getHeight(), then it works fine every time.
If I change the call to bindCameraPreview(cameraProvider) to previewView.post(()->bindCameraPreview(cameraProvider)) it works.
Not sure if this is the best/correct solution, but it's working for me. I still don't understand why my previewView has the correct dimensions the first time, and 0s the 2nd - if anyone knows, please enlighten me!
END UPDATE
Here is my ScanQRActivity:
public class ScanQRActivity extends AppCompatActivity {
private static final int PERMISSION_REQUEST_CAMERA = 0;
private PreviewView previewView;
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
private Button qrCodeFoundButton;
private String qrCode;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qr_scan);
previewView = findViewById(R.id.activity_main_previewView);
qrCodeFoundButton = findViewById(R.id.activity_main_qrCodeFoundButton);
qrCodeFoundButton.setVisibility(View.INVISIBLE);
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
requestCamera();
}
private void requestCamera() {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
startCamera();
} else {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
ActivityCompat.requestPermissions(ScanQRActivity.this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CAMERA);
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSION_REQUEST_CAMERA) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
startCamera();
} else {
// Toast.makeText(this, "Camera Permission Denied", Toast.LENGTH_SHORT).show();
}
}
}
private void startCamera() {
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
bindCameraPreview(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
Toast.makeText(this, "Error starting camera " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}, ContextCompat.getMainExecutor(this));
}
private void bindCameraPreview(#NonNull ProcessCameraProvider cameraProvider) {
previewView.setImplementationMode(PreviewView.ImplementationMode.COMPATIBLE);
Preview preview = new Preview.Builder()
.build();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
ImageAnalysis imageAnalysis =
new ImageAnalysis.Builder()
.setTargetResolution(new Size(previewView.getWidth(), previewView.getHeight() ))
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(this), new QRCodeImageAnalyzer(new QRCodeImageAnalyzer.QRCodeFoundListener() {
#Override
public void onQRCodeFound(String _qrCode) {
qrCode = _qrCode;
qrCodeFoundButton.setVisibility(View.VISIBLE);
Uri code = Uri.parse(qrCode);
if(code.getScheme().equals("myCustomScheme") && code.getHost().equals("app")){
String path = code.getPath();
String host = code.getHost() ;
String query = code.getQuery();
List<String> params = code.getQueryParameters("a");
if(path.equals("/voucher")){
Intent intent = new Intent();
intent.putExtra("type", "voucher");
intent.putExtra("voucherCode", code.getQueryParameter("c"));
intent.putExtra("timestamp", code.getQueryParameter("t"));
setResult(Activity.RESULT_OK, intent);
finish();
}
}
}
#Override
public void qrCodeNotFound() {
}
}));
Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner)this, cameraSelector,imageAnalysis, preview);
}
}
And my ActivityResultLauncher:
ActivityResultLauncher<Intent> startQRActivity = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
// Add same code that you want to add in onActivityResult method
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
String code = data.getStringExtra("voucherCode");
String time = data.getStringExtra("timestamp");
voucherDetailBusinessDialog dia = new voucherDetailBusinessDialog(getColor(R.color.appThemeColor), getColor(R.color.orange), code);
dia.show(getSupportFragmentManager(),null);
}
}
});
Related
I'm upgrading the app to target android 12, before its targeting android 10. So, now I'm using MANAGE_EXTERNAL_STORAGE with registerForActivityResult but when user allow access to manage files and press back button the registerForActivityResult do not get called. Here is my code.
In onCreate method
registerLauncher();
if (checkPermissionsGranted()) {
initMainActivity();
} else {
requestPermission();
}
The above methods in sequence.
private void registerLauncher() {
permissionLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Log.e(TAG, "inside activity result");
initMainActivity();
}
}
});
}
private boolean checkPermissionsGranted() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
int readPermission = ContextCompat.checkSelfPermission(mContext, Manifest.permission.READ_EXTERNAL_STORAGE);
int writePermission = ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE);
// int storagePermission = ContextCompat.checkSelfPermission(mContext, Manifest.permission_group.STORAGE);
return readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED;
}
}
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
try {
// Uri uri = Uri.parse("package:" + BuildConfig.APPLICATION_ID);
// Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, uri);
// startActivity(intent);
// permissionLauncher.launch(intent);
// startActivityForResult(intent, AppConstants.STORAGE_PERMISSION_CODE);
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
// startActivityForResult(intent, AppConstants.STORAGE_PERMISSION_CODE);
permissionLauncher.launch(intent);
} catch (Exception e) {
Log.e(TAG, "Exp... " + e.toString());
Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
permissionLauncher.launch(intent);
}
} else {
ActivityCompat.requestPermissions(Splashscreen.this, new String[]{Manifest.permission_group.STORAGE}, AppConstants.STORAGE_PERMISSION_CODE);
}
}
I also tried with startActivityForResult(intent, AppConstants.STORAGE_PERMISSION_CODE); (I know startActivityForResult is deprecated) with overriding onRequestPermissionsResult but none of these two get called
1 - registerForActivityResult
2 - onRequestPermissionsResult
Please let me know what I'm doing wrong here? As I'm check the permission on splash activity, the app get stuck on the splash as onResult is not being called.
Thanks & Regards
after checking the permission on splash activity, you have two options back to the App. either click on back button on the top left corner or click on app icon. but you will be get never Activity.RESULT_OK as result. Therefore, you should handle it differently by querying Environment.isExternalStorageManager().
change your registerLauncher() function as bellow.
private void registerLauncher() {
permissionLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
#Override
public void onActivityResult(ActivityResult result) {
if (Environment.isExternalStorageManager()) {
Log.e(TAG, "inside activity result");
initMainActivity();
}
}
});
}
Im trying to do something like this
i have found this pop up dialog in a few apps like shopify app and discord app , once you open sign up or login page dialog pop up with all possible emails.
Now my question how to achieve something like this without asking the user for contact permission.
My current Code is :
private void addAdapterToViews() {
Account[] accounts = AccountManager.get(getActivity()).getAccounts();
Set<String> emailSet = new HashSet<String>();
for (Account account : accounts) {
if (EMAIL_PATTERN.matcher(account.name).matches()) {
emailSet.add(account.name);
}
}
binding.autoemail.setAdapter(new ArrayAdapter<String>(getActivity(), android.R.layout.simple_dropdown_item_1line, new ArrayList<String>(emailSet)));
}
private boolean mayRequestContacts() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return true;
}
if (getActivity().checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
return true;
}
if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
Snackbar.make(binding.autoemail, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
.setAction(android.R.string.ok, new View.OnClickListener() {
#Override
#TargetApi(Build.VERSION_CODES.M)
public void onClick(View v) {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
});
} else {
requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
}
return false;
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == REQUEST_READ_CONTACTS) {
if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
addAdapterToViews();
}
}
}
This code is working fine for me once the user try to type any letters in email edittext if permission is granted.
Credentials API to retrieve sign-in hints, such as the user's name and email address.
On Android 6.0 (Marshmallow) and newer, your app does not need to request any device or runtime permissions to retrieve sign-in hints with the Credentials API
HintRequest hintRequest = new HintRequest.Builder()
.setHintPickerConfig(new CredentialPickerConfig.Builder()
.setShowCancelButton(true)
.build())
.setEmailAddressIdentifierSupported(true)
.setAccountTypes(IdentityProviders.GOOGLE)
.build();
PendingIntent intent = mCredentialsClient.getHintPickerIntent(hintRequest);
try {
startIntentSenderForResult(intent.getIntentSender(), RC_HINT, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "Could not start hint picker Intent", e);
}
HintRequest Builder Google Documentation
Maybe this is not what you are looking for, but I really recommend that you take a look to Authentication with Firebase and the helper library FirebaseUI. They have all that boilerplate already implemented and it is really easy to config, customize and setup.
its not possible to get access user confidential information (like email id ) without runtime Permissions.
So far what i have found out is using google service to get all of the user emails without any permission with the following code :
private static final int RC_SIGN_IN = 100;
Inside OnCreate() or Button click :
AuthUI.SignInIntentBuilder builder = AuthUI.getInstance().createSignInIntentBuilder();
if (getSelectedTosUrl() != null && getSelectedPrivacyPolicyUrl() != null) {
builder.setTosAndPrivacyPolicyUrls(getSelectedTosUrl(), getSelectedPrivacyPolicyUrl());
}
builder.build();
startActivityForResult(builder.build(), RC_SIGN_IN);
And to get results
#Nullable
private String getSelectedPrivacyPolicyUrl() {
return null;
}
#Nullable
private String getSelectedTosUrl() {
return null;
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == RC_SIGN_IN) {
handleSignInResponse(resultCode, data);
}
}
private void handleSignInResponse(int resultCode, #Nullable Intent data) {
IdpResponse response = IdpResponse.fromResultIntent(data);
// Successfully signed in
if (resultCode == RESULT_OK) {
// startSignedInActivity(response);
// finish();
Log.e(TAG, String.valueOf(response));
} else {
// Sign in failed
if (response == null) {
// User pressed back button
// showSnackbar(R.string.sign_in_cancelled);
Log.e(TAG, "Sign-in error: failed");
return;
}
if (response.getError().getErrorCode() == ErrorCodes.NO_NETWORK) {
// showSnackbar(R.string.no_internet_connection);
Log.e(TAG, "Sign-in error: no net");
return;
}
// showSnackbar(R.string.unknown_error);
Log.e(TAG, "Sign-in error: ", response.getError());
}
}
But my problem is that the user email dialog open in pre made sign in activty, but i would like to use my own.
Any tips ? here is the source google library
I am attempting to implement Google Play Game Services into the Android backend of my libGDX game. I used the same implementation (same helper methods, private classes, etc) as the TypeANumber module in the android-basic-samples, Google's official examples for implementing Google Play Game Services, with one main difference. In my signInSilently helper method, I changed it so that if the silentSignIn task fails, the method calls startSignIn (starts sign in intent with interactive UI) instead of onDisconnected (which sets the AchievementClient, LeaderBoardClient, and PlayersClient to null).
I did this because in a lot of games I've seen (ie Dune!), they often try the silentSignIn and start the SignIn intent if the silentSignIn is unsuccessful. However, now, whenever I start my game, the silentSignIn fails and defaults to the interactive UI. But the UI appears to fail and start up repeatedly, only to fail again and the user is flooded with AlertDialogs indicating that the error code is 13.
I'm not really sure what I've done wrong and I'm wondering how I'm correctly supposed to implement Google Play Game Services. I am using Admob so I have a RelativeLayout and I do have all my ID's in a games-ids.xml file.
onConnected helper method
private void onConnected(GoogleSignInAccount googleSignInAccount) {
mAchievementsClient = Games.getAchievementsClient(this,
googleSignInAccount);
mLeaderboardsClient = Games.getLeaderboardsClient(this,
googleSignInAccount);
mPlayersClient = Games.getPlayersClient(this,
googleSignInAccount);
// Set the greeting appropriately on main menu
mPlayersClient.getCurrentPlayer()
.addOnCompleteListener(new OnCompleteListener<Player>() {
#Override
public void onComplete(#NonNull Task<Player> task) {
String displayName;
if (task.isSuccessful()) {
displayName = task.getResult().getDisplayName();
} else {
displayName = "???";
}
}
})
;
onDisconnected helper method
private void onDisconnected() {
mAchievementsClient = null;
mLeaderboardsClient = null;
mPlayersClient = null;
}
startSignInIntent helper method
private void startSignInIntent() {
startActivityForResult(mSignInClient.getSignInIntent(), RC_SIGN_IN);
}
signInSilently helper method
private void signInSilently() {
mSignInClient.silentSignIn().addOnCompleteListener(this, new OnCompleteListener<GoogleSignInAccount>() {
#Override
public void onComplete(#NonNull Task<GoogleSignInAccount> task) {
if (task.isSuccessful()) {
// The signed in account is stored in the task's result.
onConnected(task.getResult());
} else {
//Use interactive UI to sign player in
startSignInIntent();
}
}
});
}
onActivityResult override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task =
GoogleSignIn.getSignedInAccountFromIntent(intent);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
onConnected(account);
} catch (ApiException apiException) {
String message = apiException.getMessage();
if (message == null || message.isEmpty()) {
message = SIGNIN_OTHER_ERROR;
}
onDisconnected();
new AlertDialog.Builder(this)
.setMessage(message)
.setNeutralButton(android.R.string.ok, null)
.show();
}
}
}
onCreate override
protected void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mSignInClient = GoogleSignIn.getClient(this, new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN).build());
AndroidApplicationConfiguration config = new AndroidApplicationConfiguration();
config.useAccelerometer = false;
config.useCompass = false;
//replaces initialize()
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
RelativeLayout layout = new RelativeLayout(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
layout.setLayoutParams(params);
mAdViewTopBanner = createAdView(AD_UNIT_ID_BANNER_TOP, ADVIEW_ID, RelativeLayout.ALIGN_PARENT_TOP);
View gameView = createGameView(config);
layout.addView(gameView);
layout.addView(mAdViewTopBanner);
setContentView(layout);
MobileAds.initialize(this, AD_APP_ID);
mInterstitialAd = new InterstitialAd(this);
mInterstitialAd.setAdUnitId(AD_UNIT_ID_INTERSTITIAL);
mInterstitialAd.loadAd(new AdRequest.Builder().build());
mInterstitialAd.setAdListener(new AdListener() {
#Override
public void onAdClosed() {
mInterstitialAd.loadAd(new AdRequest.Builder().build());
}
});
mAdViewTopBanner.setVisibility(View.GONE);
mAdViewTopBanner.loadAd(new AdRequest.Builder().build());
}
onActivityResult ovverride
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task =
GoogleSignIn.getSignedInAccountFromIntent(intent);
try {
GoogleSignInAccount account = task.getResult(ApiException.class);
onConnected(account);
} catch (ApiException apiException) {
String message = apiException.getMessage();
if (message == null || message.isEmpty()) {
message = SIGNIN_OTHER_ERROR;
}
onDisconnected();
new AlertDialog.Builder(this)
.setMessage(message)
.setNeutralButton(android.R.string.ok, null)
.show();
}
}
}
onResume override
public void onResume() {
super.onResume();
signInSilently();
mAdViewTopBanner.resume();
}
I know it's a lot of code to read through so huge thank you for helping out!
You must not call the non-silent login methods on game start. It is no valid reason to do something wrong just because others also do wrong. If you do it this way, your game will not be useable on devices without with outdated Play Services or without GPGS app.
For using Play Games with libGDX, you can use my extension. If you don't want to use it for whatever reasons, pick the working code from GpgsClient class.
I have this code which i make using official developer android sites. I want to create camera preview, but first ask for permissions. When i start the app they crash, but before app exit, they ask me for permissions which i grant, and then app crash. After i enter app again it work just fine, but i want to get rid of that crash. Anyone know a solution?
CameraActivity.java
public class CameraActivity extends AppCompatActivity {
private Camera mCamera;
private CameraPreview mPreview;
private static final int PERMISSION_CAMERA = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CAMERA)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
PERMISSION_CAMERA);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_CAMERA: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
#Override
public void onPause() {
super.onPause();
// Stop camera access
releaseCamera();
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
}
Logcat
FATAL EXCEPTION: main
Process: com.example.ivan.cameratest1, PID: 7690
java.lang.NullPointerException: Attempt to invoke virtual method 'void android.hardware.Camera.setPreviewDisplay(android.view.SurfaceHolder)' on a null object reference
at com.example.ivan.cameratest1.CameraPreview.surfaceCreated(CameraPreview.java:36)
at android.view.SurfaceView.updateWindow(SurfaceView.java:656)
at android.view.SurfaceView$3.onPreDraw(SurfaceView.java:172)
at android.view.ViewTreeObserver.dispatchOnPreDraw(ViewTreeObserver.java:1013)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2542)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1537)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7183)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:959)
at android.view.Choreographer.doCallbacks(Choreographer.java:734)
at android.view.Choreographer.doFrame(Choreographer.java:670)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:945)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1496)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1386)
private final String TAG = "Debug_MainActivity";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkCameraPermission();
}
private final int MY_PERMISSIONS_REQUEST_USE_CAMERA = 0x00AF;
private void checkCameraPermission(){
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA ) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG,"Permission not available requesting permission");
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST_USE_CAMERA);
} else {
Log.d(TAG,"Permission has already granted");
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_USE_CAMERA: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG,"permission was granted! Do your stuff");
} else {
Log.d(TAG,"permission denied! Disable the function related with permission.");
}
return;
}
}
}
I think you are getting an error with permission.. You are trying to open camera even when you don't have permission to. That's why it crashes on first start up and not on second time.
Try to perform the changes below (I changed onCreate and onRequestPermissionsResult):
public class CameraActivity extends AppCompatActivity {
private Camera mCamera;
private CameraPreview mPreview;
private static final int PERMISSION_CAMERA = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.CAMERA},
PERMISSION_CAMERA);
}
} else {
mCamera = getCameraInstance();
}
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_CAMERA: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mCamera = getCameraInstance();
}
return;
}
}
}
...
}
Hello to all programmers.
While creating my first android app in Visual studio Xamarin, I stuck with one more problem (there was lot of them =) ). I try to make permissions check for Android Marshmallow+. And while I try to launch Camera Activity (MediaStore.ActionImageCapture), my app crashes. Here the code
const int REQUEST_CAMERA = 1;
const int REQUEST_EXTERNAL_STORAGE = 2;
const string cameraPermission = Android.Manifest.Permission.Camera;
const string storageWritePermission = Android.Manifest.Permission.WriteExternalStorage;
const string storageReadPermission = Android.Manifest.Permission.ReadExternalStorage;
public static class App
{
public static File _file;
public static File _dir;
public static Bitmap bitmap;
public static string fileName;
}
private bool IsThereAnAppToTakePicture()
{
Intent intent = new Intent(MediaStore.ActionImageCapture);
IList<ResolveInfo> availableActivities =
PackageManager.QueryIntentActivities(intent, PackageInfoFlags.MatchDefaultOnly);
return availableActivities != null && availableActivities.Count > 0;
}
private void CreateDirectoryForPictures()
{
App._dir = new File(Enviroment.GetExternalStoragePublicDirectory(Enviroment.DirectoryPictures), "Kuponguru");
if (!App._dir.Exists())
{
App._dir.Mkdirs();
}
}
private void StartCameraActivity()
{
Intent intent = new Intent(MediaStore.ActionImageCapture);
App.fileName = String.Format("picture_{0}.jpg", Guid.NewGuid());
App._file = new File(App._dir, App.fileName);
intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(App._file));
StartActivityForResult(intent, REQUEST_CAMERA);
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.TakePicture);
pictureImageButton = FindViewById<ImageView>(Resource.Id.pictureButton);
pictureImageButton.Click += TakePicture;
if (Build.VERSION.SdkInt >= BuildVersionCodes.M)
{
if (CheckSelfPermission(storageReadPermission) == (int)Permission.Granted &&
CheckSelfPermission(storageWritePermission) == (int)Permission.Granted)
{
if (IsThereAnAppToTakePicture())
{
CreateDirectoryForPictures();
}
}
else
{
RequestPermissions(new string[] { storageWritePermission, storageReadPermission }, REQUEST_EXTERNAL_STORAGE);
}
}
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, Permission[] grantResults)
{
switch (requestCode)
{
case REQUEST_EXTERNAL_STORAGE:
{
if (grantResults[0] == Permission.Granted)
{
if (IsThereAnAppToTakePicture())
{
CreateDirectoryForPictures();
}
}
}
break;
case REQUEST_CAMERA:
{
if (grantResults[0] == Permission.Granted)
{
StartCameraActivity();
}
}
}
}
private void TakePicture(object sender, EventArgs e)
{
if (Build.VERSION.SdkInt >= BuildVersionCodes.M) {
if (CheckSelfPermission(cameraPermission) == (int)Permission.Granted &&
CheckSelfPermission(storageWritePermission) == (int)Permission.Granted)
{
StartCameraActivity();
}
else
{
RequestPermissions(new string[] { cameraPermission, storageWritePermission }, REQUEST_CAMERA);
}
}
else
{
StartCameraActivity();
}
}
If I delete string intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(App._file)); in StartCameraActivity, then camera works, but with this command app crashed.
I'll be appreciated for all suggestions.
--UPDATED--
I check Uri.FromFile(App._file) in intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(App._file)); File is not exists So, problem is - app can't create file (but can create directory)
--UPDATED--
I check application on Marshmallow emulator. All works fine. Also I check on emulated device - file, where camera should save photo, is not exists when I send it to Camera activity in intent.PutExtra(MediaStore.ExtraOutput, Uri.FromFile(App._file)); Well problem is still here.
--UPDATED--
Added try catch for Camera activity start and get exception file:///storage/emulated/0/Pictures/MyApp/picture_123.jpg exposed beyond app through ClipData.Item.getUri
At least I found whats wrong. It's god damned version issue. In Android N+ there are no more file:// URIs, only content:// URIs instead. That's why Camera Activity can't work with Uri.FromFile(App._file).
For this solution I have to thank request Answer of question by questioner SuperThomasLab and users Pkosta, hqzxzwb and Java coder
The solution, changed for VS Xamarin, I used:
**Solution **
protected override void OnCreate(Bundle savedInstanceState){
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.SetVmPolicy(builder.Build());
base.OnCreate(savedInstanceState);
...
}
Other code is without changes.
I tried it on Android N 7.1.1 on real device and it's works.
Thanks to all, who take attention to my problem.