Open Android credentials Setup programmatically - android

To display sensible data users can enable authentication in my app. I am using the android in-build authentication.
However, if the user did not secure his device using any pattern, pin, password or biometric authentication, I would like to open the android settings, where he can setup his authentication. Is there any Intent/ way to go there? I did not find it.
Some code so far:
To determine, if the user did not setup any authentication method:
androidx.biometric.BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) activity, executor, new BiometricPrompt.AuthenticationCallback() {
#Override
public void onAuthenticationError(int errorCode, #NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
// Determine, if the user has no device password set.
boolean errorCodeIsBeingHandledSeparately = false;
// HERE WE DETERMINE THAT CREDENTIALS HAVE NOT BEEN SETUP
if (errorCode == BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL) {
if (authenticationInterface != null) {
errorCodeIsBeingHandledSeparately = true;
authenticationInterface.onUserHasNoDevicePassWordSet();
}
}
// Display error message, only if the error code is not being handled seperately.
if (!errorCodeIsBeingHandledSeparately) {
Toast.makeText(activity, "Authentication error\n" + errString, Toast.LENGTH_LONG).show();
}
}
#Override
public void onAuthenticationSucceeded(#NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
if (authenticationInterface == null) {
Toast.makeText(activity, "Success", Toast.LENGTH_LONG).show();
}
else {
authenticationInterface.onUserSuccessfullyAuthenticated();
}
}
#Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
Toast.makeText(activity, "Authentication failed", Toast.LENGTH_LONG).show();
}
});
The interface to receive authentication return.
/**
* Interface to receive authentication return.
*/
private AuthenticationUtils.AuthenticationInterface authenticationInterface;
public interface AuthenticationInterface {
public void onUserSuccessfullyAuthenticated();
public void onUserHasNoDevicePassWordSet();
}
The dialog where I want to lead the user to go to the device setup credentials.
public void displayNoDeviceCredentialsSetDialog() {
MaterialAlertDialogBuilder noDeviceCredentialsDialog = new MaterialAlertDialogBuilder(activity, R.style.AlertDialogTheme);
String noDeviceCredentials_goToSettings_dialogMessage = activity.getString(R.string.authentication_noDeviceCredentials_goToSettings_dialogMessage);
noDeviceCredentialsDialog.setMessage(noDeviceCredentials_goToSettings_dialogMessage);
noDeviceCredentialsDialog.setPositiveButton(
R.string.DialogConfirmationOK,
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// HERE I WOULD LIKE TO OPEN THE ANDROID SETTING WHERE HE CAN SETUP HIS CREDENTIALS
}
}
);
noDeviceCredentialsDialog.setNegativeButton(
R.string.DialogConfirmationNegativeAnswerText,
null
);
noDeviceCredentialsDialog.show();
}
I would like to go here:
You can get there from settings here:
What i am looking for is something like this: Here we navigate the user to some other android settings.
Intent intent2 = new Intent();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent2.setAction(android.provider.Settings.ACTION_APPLICATION_SETTINGS);
intent2.putExtra(android.provider.Settings.EXTRA_APP_PACKAGE, getPackageName());
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
intent2.setAction(android.provider.Settings.ACTION_APPLICATION_SETTINGS);
intent2.putExtra("app_package", getPackageName());
intent2.putExtra("app_uid", getApplicationInfo().uid);
} else {
intent2.setAction(android.provider.Settings.ACTION_APPLICATION_SETTINGS);
intent2.addCategory(Intent.CATEGORY_DEFAULT);
intent2.setData(Uri.parse("package:" + getPackageName()));
}
startActivity(intent2);

Just figured it out.
There are 3 viable options to use: Settings.ACTION_BIOMETRIC_ENROLL, Settings.ACTION_FINGERPRINT_ENROLL and Settings.ACTION_SECURITY_SETTINGS.
Final implementation I use is:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
activity.startActivity(new Intent(Settings.ACTION_BIOMETRIC_ENROLL));
}
else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
activity.startActivity(new Intent(Settings.ACTION_FINGERPRINT_ENROLL));
}
else {
activity.startActivity(new Intent(Settings.ACTION_SECURITY_SETTINGS));
}
}
Settings.ACTION_FINGERPRINT_ENROLL opens this: After chosing backup lock screen method and setup the chosen method, the device will ask you to register a fingerprint.
Settings.ACTION_SECURITY_SETTINGS opens this:
In lack of a device higher than Android Build "R" I could not test ACTION_BIOMETRIC_ENROLL, but I presume it will be similar to ACTION_FINGERPRINT_ENROLL.
If you want to see what options there are to open android settings. You can just use "CTRL" + "mouse click" on any Settings.XXX (ACTION_SECURITY_SETTINGS, ACTION_FINGERPRINT_ENROLL, ...) in Android Studio.
You will then see "..\android\platforms\android-31\android.jar!\android\provider\Settings.class"
In case you struggle to figure out which API version is described with "Build.VERSION_CODES.P" you can also click "CTRL" + "Mose Click" on the Build version (P, O, ...).
You will then see this:

Related

BiometricPrompt in android is not supporting exit on back button

I am using android provided BiometricPrompt class to provide Biometric Authentication in our application it works fine but when i click on back button of phone then blank page is getting displayed. Instead I want app to be closed onclick of back button. Any pointers will be helpful.,
public class FingerprintLoginActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BiometricPrompt biometricPrompt = new BiometricPrompt(this, Executors.newSingleThreadExecutor(), new BiometricPrompt.AuthenticationCallback() {
#Override
public void onAuthenticationError(int errorCode, #NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
if (errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON) {
// user clicked negative button
} else {
// TODO: Called when an unrecoverable error has been encountered and the operation is complete.
}
}
#Override
public void onAuthenticationSucceeded(#NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
//TODO: Called when a biometric is recognized.
Context.Fingerprint = true;
Intent fingerprintIntent = new Intent(FingerprintLoginActivity.this, MainActivity.class);
fingerprintIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(fingerprintIntent);
}
#Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
//TODO: Called when a biometric is valid but not recognized.
}
});
BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
.setTitle("touch to fingerprint scanner")
.setNegativeButtonText("Cancel")
.build();
biometricPrompt.authenticate(promptInfo);
}
}
I implement based on the instructions given here and here. The back button works fine for me: the dialog/prompt simply closes and I'm back to the Activity. Do you recognize the blank page you are seeing? perhaps you are implementing the API in a blank Activity? Try following the blog posts mentioned above and let us know how it goes.
UPDATE: based on your edit
Since you want to exit the Activity when the user clicks the back button, you have to handle BiometricPrompt.ERROR_USER_CANCELED in your code by calling finish():
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
super.onAuthenticationError(errorCode, errString)
Log.d(TAG, "onAuthenticationError -> $errorCode :: $errString")
if (errorCode == BiometricPrompt.ERROR_NEGATIVE_BUTTON) {
loginWithPassword()
}else if(errorCode == BiometricPrompt.ERROR_USER_CANCELED){
finish()
}
}
For dismiss the Fingerprint dialog, you must call to:
biometricPrompt.cancelAuthentication()

AlertDialog showing unexpectedly

in my app I have a permissions method that checks and asks for permissions if build codes are >= 23, I have implemented AlertDialog to achieve this and show rationale if needed. The problem is when I test on lollipop a dialog window with the app's name pops up every time the app is started, I have fully protected all methods involved to not do anything if build codes are less than 23, so how and why is this dialog box still showing? Here's an image of the rouge dialog box:
And here is all the related code:
public void GMASInit() {
linkGms = RunnerActivity.CurrentActivity;
linkGms.startActivity(new Intent(linkGms, AudioSave.class));
}
protected void onStart() {//RunnerJNILib.ms_context
super.onStart();
if (Build.VERSION.SDK_INT >= 23) {
getPerms();
}
//other unrelated code.....
}
public void getPerms() {
if (Build.VERSION.SDK_INT >= 23) {
try { // Determine weather developer included optional WRITE_SETTINGS permission in the manifest
PackageInfo info = getPackageManager().getPackageInfo(linkGms.getPackageName(), PackageManager.GET_PERMISSIONS);
if (info.requestedPermissions != null) {
for (String p : info.requestedPermissions) {
if (p.contains("WRITE_SETTINGS")) {
perms = 3;
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
final List<String> permissionsList = new ArrayList<String>();
if(!addPermission(permissionsList, Manifest.permission.RECORD_AUDIO)) {permissionsNeeded.add("Record Audio");}
if(!addPermission(permissionsList, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {permissionsNeeded.add("Write storage");}
Log.i("yoyo","Number of permissions in manifest: " + String.valueOf(perms));
if (permissionsList.size() > 0) {
if (permissionsNeeded.size() > 0) {
if (perms == 2) {
message = message + " " + msg1 + " and " + msg2 + " " + "to save and load data and record audio.";
}
if (perms == 3) {
message = message + " " + msg1 + ", " + msg2 + " and " + msg3 + " " + "to save and load data, record audio and change ringtone.";
}
Log.i("yoyo","Message to be shown: " + message);
showMessageOKCancel(message, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface arg0, int arg1) {
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.System.canWrite(linkGms) && perms == 3) {
Intent writeset = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
writeset.setData(Uri.parse("package:" + linkGms.getPackageName()));
linkGms.startActivity(writeset);
}
linkGms.requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), Get_Permission);
finish();
}
}
});
return;
}
}
finish();
}
}
private boolean addPermission(List<String> permissionsList, String permission) {
if (Build.VERSION.SDK_INT >= 23) {
if (linkGms.checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
permissionsList.add(permission);
if (!linkGms.shouldShowRequestPermissionRationale(permission))
return false;
}
}
return true;
}
private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {
if (Build.VERSION.SDK_INT >= 23) {
new AlertDialog.Builder(linkGms).setTitle(msg0).setMessage(message).setPositiveButton("OK", okListener).setNegativeButton("Cancel", null).create().show();
}
}
As you can see I've gone overkill in trying to prevent this problem, Also note that it's only this dialog box showing (the one in the picture), the permissions dialog box does not show (which is expected). Also more info that might be helpfull/related is when testing android os 23 and up the dialog box I showed you shows above the permissions dialog box, and you have to click outside of it to dismiss it so the actual permissions dialog box can be accessed. please tell me where I've gone wrong and how to fix it, thanks.
I figured it out, it was a strange situation indeed, it had nothing to do with the permissions or alert dialog builder at all, if fact I discovered it by removing all those methods and the alert dialog imports and it still happened, so instead the problem was related to my manifest activity level style code statement. I have this activity statement in my manifest:
<activity android:name=".AudioSave"
android:theme="#android:style/Theme.Holo.Dialog" >
</activity>
So this was causing a conflict with how I have to call the onStart method, but I need the theme for my app, so all I had to do to fix it was to add finish(); before the last closing curly bracket at the end of my onStart method. problem solved, like this:
protected void onStart() {
super.onStart();
//bla bla bla...
finish();
}

Android fingerprint api - FingerprintManager.AuthenticationCallback not called after SCREEN_ON intent

I'm writing an app that authenticates the user using the native Android Fingerprint API (on Android 6.0 and up).
In one scenario - the device receives a Gcm notification and if the screen is off but the phone is not locked - the app "wakes" the device by launching an activity with the following flags:
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
The app then displays a dialogs that asks the user to authenticate using his finger. In this case - no callback function (from FingerprintManager.AuthenticationCallback - ) is called
here is the code :
fingerprintManager.authenticate(null, cancellationSignal, 0, new FingerprintManager.AuthenticationCallback() {
#Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
logger.info("Authentication error " + errorCode + " " + errString);
...
}
#Override
public void onAuthenticationHelp(int helpCode, CharSequence helpString) {
super.onAuthenticationHelp(helpCode, helpString);
logger.info("Authentication help message thrown " + helpCode + " " + helpString);
...
}
#Override
public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
logger.info("Authentication succeeded");
...
}
/*
* Called when authentication failed but the user can try again
* When called four times - on the next fail onAuthenticationError(FINGERPRINT_ERROR_LOCKOUT)
* will be called
*/
#Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
logger.info("Authentication failed");
...
}
}, null);
The same code runs when the screen is on and when it's off but when it's off and turned on by the activity - the callbacks don't get called.
Any ideas?
Thanks in advance!
I've noticed the same issue and in the adb logcat I've seen the next line:
W/FingerprintManager: authentication already canceled
I've searched in depth into source code and I've found the following function in FingerprintManager:
if (cancel != null) {
if (cancel.isCanceled()) {
Log.w(TAG, "authentication already canceled");
return;
} else {
cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
}
}
This means, that you are entering your authenticate() function with already cancelled cancellationSignal. Just add the following before your authenticate():
if(cancellationSignal.isCanceled()){
cancellationSignal = new CancellationSignal();
}
This way you will always pass the non-cancelled cancellationSignal and your flow will be correct.

There are multiple apps registered for the AuthActivity URI scheme - Dropbox sync issue on Android

Sorry for my poor English and the fact I am a newbie on Android development.
I'm developping an Android app which should send data to the datastore of Dropbox. My problem is, when my code is getting this line:
mAccountManager.startLink(DropboxHelper.this,REQUEST_LINK_TO_DBX);
Then my logcat send me the message below:
10-19 10:40:32.411: W/com.dropbox.client2.android.AuthActivity(28381): There are multiple
apps registered for the AuthActivity URI scheme (db-qeojdcjk0dkkswc). Another app may be
trying to impersonate this app, so authentication will be disabled.
The closer explanation I have found is this one:
Android + DropboxSync startLink
But the comments have not helped me.
Here my code :
public class DropboxHelper extends ActionBarActivity {
// *** Objects and APP_KEY + APP_SECRET are instantiate here ***
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.dropbox_activity);
// Set up the account manager
mAccountManager = DbxAccountManager.getInstance(getApplicationContext(), APP_KEY, APP_SECRET);
mUnlinkButton = (Button) findViewById(R.id.unlink_button);
mUnlinkButton.setVisibility(View.GONE);
// Button to link to Dropbox
mLinkButton = (Button) findViewById(R.id.link_button);
mLinkButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if ( mAccountManager.getLinkedAccount() == null )
mAccountManager.startLink(DropboxHelper.this, REQUEST_LINK_TO_DBX);
else
{
Toast.makeText(DropboxHelper.this, "Connection déjà établie, vous pouvez vous déconnecter si vous le souhaitez", Toast.LENGTH_LONG).show();
mUnlinkButton.setVisibility(View.VISIBLE);
}
}
});
mUnlinkButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mAccountManager.unlink();
Toast.makeText(DropboxHelper.this, "Déconnecté", Toast.LENGTH_LONG).show();
}
});
// Set up the datastore manager
if (mAccountManager.hasLinkedAccount()) {
try {
// Use Dropbox datastores
mDatastoreManager = DbxDatastoreManager.forAccount(mAccountManager.getLinkedAccount());
mLinkButton.setVisibility(View.GONE);
} catch (DbxException.Unauthorized e) {
System.out.println("Account was unlinked remotely");
}
}
if (mDatastoreManager == null) {
// Account isn't linked yet, use local datastores
mDatastoreManager = DbxDatastoreManager.localManager(mAccountManager);
// Show link button
mLinkButton.setVisibility(View.VISIBLE);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_LINK_TO_DBX) {
if (resultCode == Activity.RESULT_OK) {
account = mAccountManager.getLinkedAccount();
try {
// Migrate any local datastores to the linked account
mDatastoreManager.migrateToAccount(account);
// Now use Dropbox datastores
mDatastoreManager = DbxDatastoreManager.forAccount(account);
// Hide link button
mLinkButton.setVisibility(View.GONE);
} catch (DbxException e) {
e.printStackTrace();
}
} else {
// Link failed or was cancelled by the user
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
I can't figure out How to solve this issue, I really thank you If you can help me.
Best regards.
This generally means you have more than one app installed using the same app key. Often, this can happen if you have, for example, a sample app from the SDK as well as the app you're developing installed on the same device (or virtual device) using your app key. The solution is just to uninstall one of the apps, or use a different app key in one of them.

Android No Activity found to handle intent

I am basing my app off the foursquare-oAuth-sample app posted at Foursquare oAuth sample
Have made changes to MyActivity pretty much similar to the sample code but still getting this, can someone point out what I need to change, the code is as below
public class MyActivity extends FragmentActivity {
private static final int REQUEST_CODE_FSQ_CONNECT = 200;
private static final int REQUEST_CODE_FSQ_TOKEN_EXCHANGE = 201;
/**
* Obtain your client id and secret from:
* https://foursquare.com/developers/apps
*/
private static final String CLIENT_ID = "";
private static final String CLIENT_SECRET = "";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
ensureUi();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* Update the UI. If we already fetched a token, we'll just show a success
* message.
*/
private void ensureUi() {
boolean isAuthorized = !TextUtils.isEmpty(ExampleTokenStore.get().getToken());
TextView tvMessage = (TextView) findViewById(R.id.tvMessage);
tvMessage.setVisibility(isAuthorized ? View.VISIBLE : View.GONE);
Button btnLogin = (Button) findViewById(R.id.btnLogin);
btnLogin.setVisibility(isAuthorized ? View.GONE : View.VISIBLE);
btnLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Start the native auth flow.
Intent intent = FoursquareOAuth.getConnectIntent(MyActivity.this, CLIENT_ID);
// If the device does not have the Foursquare app installed, we'd
// get an intent back that would open the Play Store for download.
// Otherwise we start the auth flow.
if (FoursquareOAuth.isPlayStoreIntent(intent)) {
toastMessage(MyActivity.this, getString(R.string.app_not_installed_message));
startActivity(intent);
} else {
startActivityForResult(intent, REQUEST_CODE_FSQ_CONNECT);
}
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CODE_FSQ_CONNECT:
onCompleteConnect(resultCode, data);
break;
case REQUEST_CODE_FSQ_TOKEN_EXCHANGE:
onCompleteTokenExchange(resultCode, data);
break;
default:
super.onActivityResult(requestCode, resultCode, data);
}
}
private void onCompleteConnect(int resultCode, Intent data) {
AuthCodeResponse codeResponse = FoursquareOAuth.getAuthCodeFromResult(resultCode, data);
Exception exception = codeResponse.getException();
if (exception == null) {
// Success.
String code = codeResponse.getCode();
performTokenExchange(code);
} else {
if (exception instanceof FoursquareCancelException) {
// Cancel.
toastMessage(this, "Canceled");
} else if (exception instanceof FoursquareDenyException) {
// Deny.
toastMessage(this, "Denied");
} else if (exception instanceof FoursquareOAuthException) {
// OAuth error.
String errorMessage = exception.getMessage();
String errorCode = ((FoursquareOAuthException) exception).getErrorCode();
toastMessage(this, errorMessage + " [" + errorCode + "]");
} else if (exception instanceof FoursquareUnsupportedVersionException) {
// Unsupported Fourquare app version on the device.
toastError(this, exception);
} else if (exception instanceof FoursquareInvalidRequestException) {
// Invalid request.
toastError(this, exception);
} else {
// Error.
toastError(this, exception);
}
}
}
private void onCompleteTokenExchange(int resultCode, Intent data) {
AccessTokenResponse tokenResponse = FoursquareOAuth.getTokenFromResult(resultCode, data);
Exception exception = tokenResponse.getException();
if (exception == null) {
String accessToken = tokenResponse.getAccessToken();
// Success.
toastMessage(this, "Access token: " + accessToken);
// Persist the token for later use. In this example, we save
// it to shared prefs.
ExampleTokenStore.get().setToken(accessToken);
// Refresh UI.
ensureUi();
} else {
if (exception instanceof FoursquareOAuthException) {
// OAuth error.
String errorMessage = ((FoursquareOAuthException) exception).getMessage();
String errorCode = ((FoursquareOAuthException) exception).getErrorCode();
toastMessage(this, errorMessage + " [" + errorCode + "]");
} else {
// Other exception type.
toastError(this, exception);
}
}
}
/**
* Exchange a code for an OAuth Token. Note that we do not recommend you
* do this in your app, rather do the exchange on your server. Added here
* for demo purposes.
*
* #param code
* The auth code returned from the native auth flow.
*/
private void performTokenExchange(String code) {
Intent intent = FoursquareOAuth.getTokenExchangeIntent(this, CLIENT_ID, CLIENT_SECRET, code);
startActivityForResult(intent, REQUEST_CODE_FSQ_TOKEN_EXCHANGE);
}
public static void toastMessage(Context context, String message) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
}
public static void toastError(Context context, Throwable t) {
Toast.makeText(context, t.getMessage(), Toast.LENGTH_SHORT).show();
}
Error Log
Here is the exception i am getting, can someone please point out why is it not able to find the activity to handle intent? Thank you
08-13 23:15:23.137 2754-2754/com.example.panaceatechnologysolutions.farhansfoursquareapp E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.panaceatechnologysolutions.farhansfoursquareapp, PID: 2754
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.VIEW dat=market://details?id=com.example.panaceatechnologysolutions.farhansfoursquareapp&referrer=utm_source=foursquare-android-oauth&utm_term=CLIENT_ID }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1691)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1482)
at android.app.Activity.startActivityForResult(Activity.java:3711)
at android.app.Activity.startActivityForResult(Activity.java:3669)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:840)
at android.app.Activity.startActivity(Activity.java:3914)
at android.app.Activity.startActivity(Activity.java:3882)
at com.example.panaceatechnologysolutions.farhansfoursquareapp.MyActivity$1.onClick(MyActivity.java:90)
at android.view.View.performClick(View.java:4598)
at android.view.View$PerformClick.run(View.java:19268)
at android.os.Handler.handleCallback(Handler.java:738)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5070)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:836)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:631)
08-13 23:15:30.157 2754-2765/com.example.panaceatechnologysolutions.farhansfoursquareapp I/art﹕ Heap transition to ProcessStateJankImperceptible took 7.253732ms saved at least 72KB
Ok so based on Rohans reply I checked, since I was doing this on the Emulator, this snippet from the Foursquare oAuth library I have in my project cannot create the intent based on the context and client Id. I am not sure why it returns null and as a result redirects me to the Google play store to install foursquare on my emulator. I have registered my app with foursquare and am using the registered client Id and the rest of the parameters used by this function are the ones in Foursquare oAuth Java class. If someone has worked with this library or can point out why it can't find the intent please let me know as I have been stuck on this for a couple of days.
This is the line of code like Rohan pointed out calling the Foursquare oAuth Java class in MyActivity class
Intent intent = FoursquareOAuth.getConnectIntent(MyActivity.this, CLIENT_ID);
And this is the getConnectIntent method in the Foursquare oAuth Java Class
public static Intent getConnectIntent(Context context, String clientId) {
Uri.Builder builder = new Uri.Builder();
builder.scheme(URI_SCHEME);
builder.authority(URI_AUTHORITY);
builder.appendQueryParameter(PARAM_CLIENT_ID, clientId);
builder.appendQueryParameter(PARAM_VERSION, String.valueOf(LIB_VERSION));
builder.appendQueryParameter(PARAM_SIGNATURE, getSignatureFingerprint(context));
Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
if (isIntentAvailable(context, intent)) {
return intent;
}
return getPlayStoreIntent(clientId);
}
it redirects you to play store becuase "isIntentAvailable is false" and it calls "getPlayStoreIntent" which redirects you to play store.
inside isIntentAvailable method
private static boolean isIntentAvailable(Context context, Intent intent) {
PackageManager packageManager = context.getPackageManager();
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(
intent, PackageManager.MATCH_DEFAULT_ONLY);
return resolveInfo.size() > 0;
}
this method return true if a suitable package is found.
also check your client id is not null and is correct
Yes Rohan...you are right it is false because the intent wasnt returning anything from isIntentAvailable, but the real reason why that was not returning an intent back was because since I am using the emulator, the package manager is apparently looking for a foursquare.apk package installed which it didnt find. I didnt Foursquare anywhere indicate that their apk has to be installed which is not included as part of the oAuth Library which they provide in the link above on the sample project. I guess they assume you are using an Android device for testing and not the emulator. These are the steps to use oAuth from Foursquare on Android emulator from Android studio or Eclipse im guessing as well.
1) Download the Foursquare APK http://www.apk4fun.com/apk/6395/
2) As a pre-requisite open Android SDK Manager in Android studio and make sure Google API's are downloaded and installed, these are needed by Foursquare
3) copy the foursquare.apk file in the /Applications/sdk/platform-tools folder
4) install the apk using the adb tool in the folder like shown in this link How to install an apk on the emulator in Android Studio?
5) and now your app can use the emulator to contact foursquare and you will not be redirected to install the app on the emulator!
-Note, I noticed I had to reinstall the "foursquare.apk" when i closed down Android studio and the emulator the next day. But was easy since i knew what to do, Hopefully this saves someone else the frustration as it took me a couple of days to figure this out :)

Categories

Resources