I use Android SafetyNet ReCaptcha to show the Google captcha in my Android app. The problem is that when I test it, the checkboxes are never shown. Instead, the captcha is well shown, and its progress bar is animated a little, and then it finishes without any error, confirming I'm a human. This behavior is normal and there isn't any bug.
But. I would want to force the captcha, which seems to work well as I've described above, to show the checkboxes. By "checkboxes", I mean e.g. "checkboxes showing pedestrian crossings that the human user must claim to recognize by checking". The official documentation doesn't explain how to do it: https://developer.android.com/training/safetynet/recaptcha#send-request
Resources (documentation and StackOverflow)
Documentation : 1 link but unrelevant
I've followed this documentation: https://developer.android.com/training/safetynet/recaptcha#send-request . However, it doesn't give any information about how to solve my problem.
StackOverflow : 1 question but unrelevant
I haven't found any relevant question. I've not found, in fact, any question on how to implement ReCaptcha for Android, except a very short one (which doesn't provide any useful data to solve my problem).
My implementation
I'm going to show you how I've implemented their API ReCaptcha for Android (SafetyNet ReCaptcha) to help you to help me.
The process
My app's users can sign-up, sign-in, sign-out.
When a user starts my app, a splash screen appears. If the user isn't connected, he is invited to touch a button.
2.1. If he touches the button, the ReCaptcha is started.
2.1.1. If the ReCaptcha is successfully completed, then the user can sign-up and sign-in with his Google account (I use Google Firebase Auth and even AuthUI).
2.1.2. Otherwise, nothing occurs : he'll have to re-try to complete ReCaptcha.
Sources
SplashScreen.java (an AppCompatActivity class): The "onClick" event handler listening to the "touch" event on the button
In résumé: I attach the listener to the button. If the latter is clicked, thus, I call verifyWithRecaptcha in a (synchrone! and it's voluntary) Executor. Then I call the Google's servers to be sure the captcha has been completed by a humain being, not by a bot, thanks to my class NetworkUseRecaptcha which provides the result of the Google's servers.
final Context that = this;
button_splash_screen_recaptcha.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Executor executor = new Executor() {
#Override
public void execute(#NonNull Runnable command) {
command.run();
}
};
executor.execute(new Runnable() {
#Override
public void run() {
SafetyNet.getClient(that).verifyWithRecaptcha("PUBLIC KEY")
.addOnSuccessListener(executor,
new OnSuccessListener<SafetyNetApi.RecaptchaTokenResponse>() {
#Override
public void onSuccess(final SafetyNetApi.RecaptchaTokenResponse response) {
String userResponseToken = response.getTokenResult();
if (!userResponseToken.isEmpty()) {
String[] parameters = new String[2];
parameters[0] = "SECRET KEY";
parameters[1] = userResponseToken;
new NetworkUseRecaptcha(new RecaptchaPostExecuteCallback() {
#Override
public void onTaskCompleted(String result, boolean background_error) {
if(background_error) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(that,"Error N°2: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
});
return;
}
try {
final JSONObject json_response = new JSONObject(result);
if(!json_response.isNull("success") && json_response.getBoolean("success")) {
final List<AuthUI.IdpConfig> providers = ImmutableList.of(
new AuthUI.IdpConfig.GoogleBuilder().build()
);
startActivityForResult(
AuthUI.getInstance()
.createSignInIntentBuilder()
.setAvailableProviders(providers)
.setAlwaysShowSignInMethodScreen(true)
.setLogo(R.drawable.yellow_logo)
.setTheme(R.style.LoginTheme)
.build(),
REQUEST_CODE_SIGN_IN
);
} else {
Toast.makeText(that,"Error N°4: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(that,"Error N°3: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
});
}
}
}).execute(parameters);
}
}
})
.addOnFailureListener(executor, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
System.err.println(e);
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(that,"Error N°1: Unable to check the captcha.", Toast.LENGTH_SHORT).show();
}
});
}
});
}
});
}
});
NetworkUseRecaptcha.java: My class that allows me to contact the Google's servers to verify the captcha
class NetworkUseRecaptcha extends AsyncTask<String, Void, String> {
private final RecaptchaPostExecuteCallback post_execute_callback;
private boolean background_error;
NetworkUseRecaptcha(RecaptchaPostExecuteCallback post_execute_callback) {
this.post_execute_callback = post_execute_callback;
background_error = false;
}
#Override
protected String doInBackground(String[] parameters) {
StringBuilder string_builder = new StringBuilder();
try {
URL url = new URL("https://www.google.com/recaptcha/api/siteverify");
HttpsURLConnection https_url_connection = (HttpsURLConnection) url.openConnection();
https_url_connection.setRequestMethod("POST");
https_url_connection.setDoOutput(false);
https_url_connection.setUseCaches(false);
OutputStream os = https_url_connection.getOutputStream();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8));
writer.write("secret=" + parameters[0] + "&response=" + parameters[1]);
writer.flush();
writer.close();
os.close();
InputStream input_stream = https_url_connection.getInputStream();
BufferedReader buffered_reader = new BufferedReader(new InputStreamReader(input_stream));
String line;
while((line = buffered_reader.readLine()) != null) {
string_builder.append(line);
}
buffered_reader.close();
} catch (Exception e) {
background_error = true;
}
return string_builder.toString();
}
#Override
protected void onPostExecute(String result) {
post_execute_callback.onTaskCompleted(result, background_error);
}
}
https://developers.google.com/android/reference/com/google/android/gms/safetynet/SafetyNetClient#verifyWithRecaptcha(java.lang.String): "If reCAPTCHA is confident that this is a real user on a real device it will return a token with no challenge. Otherwise it will provide a visual/audio challenge to attest the humanness of the user before returning a token."
So my wish is impossible to concretize...
Related
I was trying to integrate the PayPal in iOS as well as Android native application for in India & Qatar, which currencies are INR & QAR, As much i know PayPal does not support such Currency so is there only option to use currency convertor?
If yes, can anybody tell me how can i achieve it step by step.
Unfortunately, PayPal does not support yet lot of currencies. See supported currency code.
Anyway if you want to achieve thing you must need to use currency convertor you can use Google API or Yahoo API for that.
You can visit here & you can talk with your backend developer regarding this he will assist you even better & easy way,
I have used it once in Android native app Yahoo exchange rates like,
Step 1:
private String fromCurrency = "QAR";
private String toCurrency = "USD";
private String urlString = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20csv%20where%20url%3D%22http%3A%2F%2Ffinance.yahoo.com%2Fd%2Fquotes.csv%3Fe%3D.csv%26f%3Dc4l1%26s%3D" + fromCurrency + toCurrency + "%3DX%22%3B&format=json";
Step 2:
private void apiCallCurrencyConversion() {
//Don't mind you can you retrofit call too,
OkHttpClient client = new OkHttpClient();
final Request request = new Request.Builder()
.url(urlString)
.build();
client.newCall(request).enqueue(new okhttp3.Callback() {
#Override
public void onFailure(#NonNull okhttp3.Call call, #NonNull IOException e) {
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this,"Fail", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onResponse(#NonNull okhttp3.Call call, #NonNull okhttp3.Response response) throws IOException {
runOnUiThread(new Runnable() {
#Override
public void run() {
}
});
if (response.code() == 200 && response.isSuccessful()) {
final CurrencyYahooApiJSON currencyYahooApiJSON = new Gson().fromJson(response.body().string(), CurrencyYahooApiJSON.class);
Log.d(TAG, currencyYahooApiJSON.getQuery().getResults().getRow().getConvertedValue());
runOnUiThread(new Runnable() {
#Override
public void run() {
proceedToPay(currencyYahooApiJSON);
}
});
}
}
});
}
You can download the ResponseJsonObject pojo from here
Now you are ready to use the converted value with USD,
Step 3:
private void proceedToPay(CurrencyYahooApiJSON currencyYahooApiJSON) {
//Getting the amount from editText
String paymentAmount = "100";
Row row = currencyYahooApiJSON.getQuery().getResults().getRow();
double val = Double.valueOf(paymentAmount);
double convertedAmount = val * Double.valueOf(row.getConvertedValue());
// convertedAmount here will us get is near about 27.41
//PayPal Configuration & payment process ahead.
}
Cheers
I want to have a Splash screen that has an inderteminate ProgressDialog and its progress gets updated by async calls from within a Presenter class (from MVP architecture).
I have a number of API calls to make to my BaaS server and for every successfull call, I would like to update the progress bar.
What's the best way to accomplish this?
I have been trying using EventBus to send notifications to my SplashActivity but it seems that all the API calls are first completed and only then the bus notifications are getting consumed and updating the UI.
What I have done so far is:
SplashActivity:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onProgressBar(String event) {
Timber.d("onProgressBar");
if(event.contains("Done")) {
roundCornerProgressBar.setProgress(100);
} else {
roundCornerProgressBar.setProgress(roundCornerProgressBar.getProgress() + 10);
}
textViewTips.setText(event);
}
Presenter:
InstanceID iid = InstanceID.getInstance(ctx);
String id = iid.getId();
mDataManager.getPreferencesHelper().putInstanceId(id);
GSUtil.instance().deviceAuthentication(id, "android", mDataManager);
GSUtil.instance().getPropertySetRequest("PRTSET", mDataManager);
GSUtil:
public void deviceAuthentication(String deviceId, String deviceOS, final DataManager mDataManager) {
gs.getRequestBuilder().createDeviceAuthenticationRequest()
.setDeviceId(deviceId)
.setDeviceOS(deviceOS)
.send(new GSEventConsumer<GSResponseBuilder.AuthenticationResponse>() {
#Override
public void onEvent(GSResponseBuilder.AuthenticationResponse authenticationResponse) {
if(mDataManager != null) {
mDataManager.getPreferencesHelper().putGameSparksUserId(authenticationResponse.getUserId());
}
EventBus.getDefault().post("Reading player data");
}
});
}
public void getPropertySetRequest(String propertySetShortCode, final DataManager mDataManager) {
gs.getRequestBuilder().createGetPropertySetRequest()
.setPropertySetShortCode(propertySetShortCode)
.send(new GSEventConsumer<GSResponseBuilder.GetPropertySetResponse>() {
#Override
public void onEvent(GSResponseBuilder.GetPropertySetResponse getPropertySetResponse) {
GSData propertySet = getPropertySetResponse.getPropertySet();
GSData scriptData = getPropertySetResponse.getScriptData();
try {
JSONObject jObject = new JSONObject(propertySet.getAttribute("max_tickets").toString());
mDataManager.getPreferencesHelper().putGameDataMaxTickets(jObject.getInt("max_tickets"));
jObject = new JSONObject(propertySet.getAttribute("tickets_refresh_time").toString());
mDataManager.getPreferencesHelper().putGameDataTicketsRefreshTime(jObject.getLong("refresh_time"));
} catch (JSONException e) {
e.printStackTrace();
}
EventBus.getDefault().post("Game data ready");
EventBus.getDefault().post("Done!");
}
});
}
Right now I am just showing you 2 API calls, but I will need another 2.
Thank you
I found the answer! It's easier that I thought, which is unfortunate as I spend about 4 hours on this:
First, I created two new methods on my MVPView interface:
public interface SplashMvpView extends MvpView {
void updateProgressBarWithTips(float prog, String tip);
void gameDataLoaded();
}
Then, in the presenter itself, I call every API call and for every call, I update the View with the updateProgressBarWithTips method and when everything is completed, I finalise it so I can move from Splash screen to Main screen:
private void doGSData(String id) {
getMvpView().updateProgressBarWithTips(10, "Synced player data");
GSAndroidPlatform.gs().getRequestBuilder().createDeviceAuthenticationRequest()
.setDeviceId(id)
.setDeviceOS("android")
.send(new GSEventConsumer<GSResponseBuilder.AuthenticationResponse>() {
#Override
public void onEvent(GSResponseBuilder.AuthenticationResponse authenticationResponse) {
if(mDataManager != null) {
mDataManager.getPreferencesHelper().putGameSparksUserId(authenticationResponse.getUserId());
}
getMvpView().updateProgressBarWithTips(10, "Synced game data");
GSAndroidPlatform.gs().getRequestBuilder().createGetPropertySetRequest()
.setPropertySetShortCode("PRTSET")
.send(new GSEventConsumer<GSResponseBuilder.GetPropertySetResponse>() {
#Override
public void onEvent(GSResponseBuilder.GetPropertySetResponse getPropertySetResponse) {
GSData propertySet = getPropertySetResponse.getPropertySet();
GSData scriptData = getPropertySetResponse.getScriptData();
try {
JSONObject jObject = new JSONObject(propertySet.getAttribute("max_tickets").toString());
mDataManager.getPreferencesHelper().putGameDataMaxTickets(jObject.getInt("max_tickets"));
jObject = new JSONObject(propertySet.getAttribute("tickets_refresh_time").toString());
mDataManager.getPreferencesHelper().putGameDataTicketsRefreshTime(jObject.getLong("refresh_time"));
} catch (JSONException e) {
e.printStackTrace();
}
getMvpView().gameDataLoaded();
}
});
}
});
}
I hope this helps someone, if you're using MVP architecture.
Cheers
I tried implementing a signIn method from the OneDrive API, but I am not sure I correctly understood the workflow.
Basically, on first launch of the app, I want to have both the login window and the "authorise the app to..." window". But then, when the user launches the app again, I would like to be directly connected to the app, without any window.
Instead, with the following code, I keep having the second window (where the user decides to accept the app)
#Override
public void signIn() {
//personal code
linkingStarted = true;
signInStatus = SignInStatus.SIGNING_IN;
activity.setUpWait(R.layout.popup_waitgif_white);
//end of personal code
mAuthClient = AuthClientFactory.getAuthClient(activity.getApplication());
if (mAuthClient.getSession().isExpired() && Util.isConnectedToInternet(activity)) {
activity.alertOnUIThread("Login again");
activity.runOnUiThread(new Runnable() {
#Override
public void run() {
mAuthClient.login(activity, SCOPES, mAuthListener);
}
});
} else if (!Util.isConnectedToInternet(activity)) {
activity.alertOnUIThread(activity.getString(R.string.alert_verifyconnection));
} else {
activity.alertOnUIThread("Resigned In OneDrive");
signInStatus = SignInStatus.SIGNED_IN;
mAuthClient.initialize(SCOPES, new AuthListener() {
#Override
public void onAuthComplete(final AuthStatus status, final AuthSession session, final Object userState) {
if (status == AuthStatus.CONNECTED) {
authToken = session.getAccessToken();
oneDriveService = getOneDriveService();
signInStatus = SignInStatus.SIGNED_IN;
} else {
authenticationFailure();
Log.v(TAG, "Problem connecting");
}
}
#Override
public void onAuthError(final AuthException exception, final Object userState) {
//mAuthClient.login(activity, SCOPES, mAuthListener);
}
}, null, authToken);
}
}
and the AuthClientFactory is just this:
public class AuthClientFactory {
private static AuthClient authClient;
private static final String CLIENT_ID = "00000000XXXXX";
public static AuthClient getAuthClient(Context context) {
if (authClient == null)
authClient = new AuthClient(context, OneDriveOAuthConfig.getInstance(), CLIENT_ID);
return authClient;
}
}
You would have an easier time with the OneDrive SDK for Android, as authentication is a much simpler process.
final MSAAuthenticator msaAuthenticator = new MSAAuthenticator() {
#Override
public String getClientId() {
return "<msa-client-id>";
}
#Override
public String[] getScopes() {
return new String[] { "onedrive.appfolder", "wl.offline_access"};
}
}
final IClientConfig oneDriveConfig = new DefaultClientConfig.createWithAuthenticator(msaAuthenticator);
final IOneDriveClient oneDriveClient = new OneDriveClient
.Builder()
.fromConfig(oneDriveConfig)
.loginAndBuildClient(getActivity());
That will take care of the user authentication flow and then give you a service object that makes interacting with OneDrive straight-forward. See the full example application.
I'm trying to get the Salesforce REST API working with Android and new to android programming, followed the sample code to connect with SFDC http://wiki.developerforce.com/page/Getting_Started_with_the_Mobile_SDK_for_Android#Authentication
I'm trying to get a few records from SFDC and display them in the android app, looks like when the Async Call is made at "client.sendAsync(sfRequest, new AsyncRequestCallback()" - NullPointerException is thrown.
I did see a couple of similar issues online, but didn't help me. Hoping if some one would point me in the right direction to troubleshoot this. Thanks much.
public class GetAccountsActivity extends Activity {
private PasscodeManager passcodeManager;
private String soql;
private String apiVersion;
private RestClient client;
private TextView resultText;
private RestRequest sfRequest;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get Api Version
apiVersion = getString(R.string.api_version);
//Create Query
soql = "select id, name from Account limit 10";
// Setup view
setContentView(R.layout.get_accounts_activity);
((TextView) findViewById(R.id.Acc_Title)).setText(apiVersion);
// Passcode manager
passcodeManager = ForceApp.APP.getPasscodeManager();
}
#Override
public void onResume() {
super.onResume();
//Get SFClient
// Login options
String accountType = ForceApp.APP.getAccountType();
LoginOptions loginOptions = new LoginOptions(
null, // login host is chosen by user through the server picker
ForceApp.APP.getPasscodeHash(),
getString(R.string.oauth_callback_url),
getString(R.string.oauth_client_id),
new String[] {"api"});
new ClientManager(this, accountType, loginOptions).getRestClient(this, new RestClientCallback() {
#Override
public void authenticatedRestClient(RestClient client) {
if (client == null) {
ForceApp.APP.logout(GetAccountsActivity.this);
return;
}
GetAccountsActivity.this.client = client;
}
});
//Get Rest Object to query
try {
sfRequest = RestRequest.getRequestForQuery(apiVersion, soql);
//Use SF Rest Client to send the request
client.sendAsync(sfRequest, new AsyncRequestCallback(){
#Override
public void onSuccess(RestRequest request, RestResponse response){
//Check responses and display results
// EventsObservable.get().notifyEvent(EventType.RenditionComplete);
}//end onSuccess
#Override
public void onError(Exception exception) {
//printException(exception);
EventsObservable.get().notifyEvent(EventType.RenditionComplete);
}//End Exception for Async Method
});
}catch (UnsupportedEncodingException e) {
//printHeader("Could Send Query request");
//printException(e);
return;
}
}
}
enter code here
You are calling client.sendAsync from onResume() but client is not set until the authenticatedRestClient callback is called, you need to move your sendAsync call into the authenticatedRestClient callback.
how do I share my comments to facebook using socialize, I tried the following codes but it directly enters into the facebook home page its not sharing my comments...can anyone help me
here is my code,
public class TraSocializeActivity extends Activity {
/** Called when the activity is first created. */
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String entityKey = "http://www.getsocialize.com";
Entity entity = Entity.newInstance(entityKey, "Socialize");
View actionBarWrapped = Socialize.getSocializeUI().showActionBar(this, R.layout.main, entity);
setContentView(actionBarWrapped);
//this is the code for sharing my comments to facebook but its not working it allows the //user to enter the facebook directly
if(Socialize.getSocialize().isAuthenticated()) {
//Entity entity1 = Entity.newInstance("http://someurl.com", "My Entity");
String comment = "The comment to be added";
ShareOptions options = new ShareOptions();
options.setShareLocation(true);
options.setShareTo(SocialNetwork.FACEBOOK);
options.setListener(new SocialNetworkListener()
{
public void onError(Activity activity, SocialNetwork network, String message, Throwable e)
{
}
public void onBeforePost(Activity activity, SocialNetwork network)
{
}
{ // Handle before post
}
public void onAfterPost(Activity activity, SocialNetwork network)
{ // Handle after post
}
});
Socialize.getSocialize().addComment(this, entity, comment, options, new CommentAddListener()
{
public void onError(SocializeException error) {
// Handle error
}
public void onCreate(Comment comment)
{ // Handle success
}
});
}
}
}
I'll ping our devs to get you an answer tonight. Sorry for the delay; just saw your question. - DROdio