I have tried to integrate paytm using php. I followed this url for implementing paytm https://www.simplifiedcoding.net/paytm-integration-android-example/.
Then downloaded sample code of them to try. Changed all credential like MID, callback url and channel iD, etc. When running on device it open buying screen when tapping on buy button it takes to some time to load and show oops "Oops! Payment failed"
In android console i am able to get order id. Here is the code of constants.java
package simplifiedcoding.net.paytmpaymentsample;
/**
* Created by Belal on 1/10/2018.
*/
public class Constants {
public static final String M_ID = "xxxxx301208461"; //Paytm Merchand Id
we got it in paytm credentials
public static final String CHANNEL_ID = "WAP"; //Paytm Channel Id, got it in
paytm credentials
public static final String INDUSTRY_TYPE_ID = "Retail"; //Paytm industry type
got it in paytm credential
public static final String WEBSITE = "APP_STAGING";
public static final String CALLBACK_URL =
"https://pguat.paytm.com/paytmchecksum/paytmCallback.jsp";
}
here is the code API.java
package simplifiedcoding.net.paytmpaymentsample;
import retrofit2.Call;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.POST;
/**
* Created by Belal on 1/10/2018.
*/
public interface Api {
//this is the URL of the paytm folder that we added in the server
//make sure you are using your ip else it will not work
String BASE_URL = "http://10.208.1.229/paytm/";
#FormUrlEncoded
#POST("generateChecksum.php")
Call<Checksum> getChecksum(
#Field("MID") String mId,
#Field("ORDER_ID") String orderId,
#Field("CUST_ID") String custId,
#Field("CHANNEL_ID") String channelId,
#Field("TXN_AMOUNT") String txnAmount,
#Field("WEBSITE") String website,
#Field("CALLBACK_URL") String callbackUrl,
#Field("INDUSTRY_TYPE_ID") String industryTypeId
);
}
MainActivity.java code
package simplifiedcoding.net.paytmpaymentsample;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.paytm.pgsdk.PaytmOrder;
import com.paytm.pgsdk.PaytmPGService;
import com.paytm.pgsdk.PaytmPaymentTransactionCallback;
import java.util.HashMap;
import java.util.Map;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
//implementing PaytmPaymentTransactionCallback to track the payment result.
public class MainActivity extends AppCompatActivity implements
PaytmPaymentTransactionCallback {
//the textview in the interface where we have the price
TextView textViewPrice;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//getting the textview
textViewPrice = findViewById(R.id.textViewPrice);
//attaching a click listener to the button buy
findViewById(R.id.buttonBuy).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//calling the method generateCheckSum() which will generate the paytm checksum for payment
generateCheckSum();
}
});
}
private void generateCheckSum() {
//getting the tax amount first.
String txnAmount = textViewPrice.getText().toString().trim();
//creating a retrofit object.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Api.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
//creating the retrofit api service
Api apiService = retrofit.create(Api.class);
//creating paytm object
//containing all the values required
final Paytm paytm = new Paytm(
Constants.M_ID,
Constants.CHANNEL_ID,
txnAmount,
Constants.WEBSITE,
Constants.CALLBACK_URL,
Constants.INDUSTRY_TYPE_ID
);
//creating a call object from the apiService
Call<Checksum> call = apiService.getChecksum(
paytm.getmId(),
paytm.getOrderId(),
paytm.getCustId(),
paytm.getChannelId(),
paytm.getTxnAmount(),
paytm.getWebsite(),
paytm.getCallBackUrl(),
paytm.getIndustryTypeId()
);
//making the call to generate checksum
call.enqueue(new Callback<Checksum>() {
#Override
public void onResponse(Call<Checksum> call, Response<Checksum> response) {
//once we get the checksum we will initiailize the payment.
//the method is taking the checksum we got and the paytm object as the parameter
initializePaytmPayment(response.body().getChecksumHash(), paytm);
}
#Override
public void onFailure(Call<Checksum> call, Throwable t) {
}
});
}
private void initializePaytmPayment(String checksumHash, Paytm paytm) {
//getting paytm service
PaytmPGService Service = PaytmPGService.getStagingService();
//use this when using for production
//PaytmPGService Service = PaytmPGService.getProductionService();
//creating a hashmap and adding all the values required
Map<String, String> paramMap = new HashMap<>();
paramMap.put("MID", Constants.M_ID);
paramMap.put("ORDER_ID", paytm.getOrderId());
paramMap.put("CUST_ID", paytm.getCustId());
paramMap.put("CHANNEL_ID", paytm.getChannelId());
paramMap.put("TXN_AMOUNT", paytm.getTxnAmount());
paramMap.put("WEBSITE", paytm.getWebsite());
paramMap.put("CALLBACK_URL", paytm.getCallBackUrl());
paramMap.put("CHECKSUMHASH", checksumHash);
paramMap.put("INDUSTRY_TYPE_ID", paytm.getIndustryTypeId());
//creating a paytm order object using the hashmap
PaytmOrder order = new PaytmOrder(paramMap);
//intializing the paytm service
Service.initialize(order, null);
//finally starting the payment transaction
Service.startPaymentTransaction(this, true, true, this);
}
//all these overriden method is to detect the payment result accordingly
#Override
public void onTransactionResponse(Bundle bundle) {
Toast.makeText(this, bundle.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void networkNotAvailable() {
Toast.makeText(this, "Network error", Toast.LENGTH_LONG).show();
}
#Override
public void clientAuthenticationFailed(String s) {
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
#Override
public void someUIErrorOccurred(String s) {
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
#Override
public void onErrorLoadingWebPage(int i, String s, String s1) {
Toast.makeText(this, s, Toast.LENGTH_LONG).show();
}
#Override
public void onBackPressedCancelTransaction() {
Toast.makeText(this, "Back Pressed", Toast.LENGTH_LONG).show();
}
#Override
public void onTransactionCancel(String s, Bundle bundle) {
Toast.makeText(this, s + bundle.toString(), Toast.LENGTH_LONG).show();
}
}
For paytm integration there is 4 step process that you should follow. Some misleading information is given in Paytm Official documentation but you can follow this reference tutorial for lastest Paytm SDK integration 2019.
Add Paytm Dependency
Add Runtime Permission & Paytm Activity
Get Merchant ID & Secret Key
Upload Checksum Files on Server
Generate Paytm Checksum
Start Paytm Payment Transaction
Add paytm dependency
// paytm dependency
implementation('com.paytm:pgplussdk:1.2.3') {
transitive = true;
}
Add runtime permission
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
Also add this line in main Activity class
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_SMS}, 101);
}
To Generate Paytm Checksum you first need to know Order id must be unique on every transaction even in test model transaction.
Order id and customer ID must be generate from Your Server only.
For testing model you can manually give order id and customer id.
The flow of android code is as follow-
Main Activity – get order id and customer id from App UI.
Pass order id and customer id to another activity name as checksum.java
get checksum from URL by passing param.
String url ="https://www.blueappsoftware.com/payment/payment_paytm/generateChecksum.php";
String varifyurl = "https://pguat.paytm.com/paytmchecksum/paytmCallback.jsp";
// "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID"+orderId;
String param=
"MID="+mid+
"&ORDER_ID=" + orderId+
"&CUST_ID="+custid+
"&CHANNEL_ID=WAP&TXN_AMOUNT=100&WEBSITE=WEBSTAGING"+
"&CALLBACK_URL="+ varifyurl+"&INDUSTRY_TYPE_ID=Retail";
start paytm transaction by calling
Service.startPaymentTransaction(checksum.this, true, true,
checksum.this );
Please read this reference tutorial for complete process
Related
I am having a problem with the API that I have implemented to my website that is connected to an activity in the Android application that I am developing. According to the Logcat of my Android Studio,
that line 118 of the ForgotPassword.java of my Android application
is throwing the java.lang.AssertionError. I have studied the problem again, then learned that the response of the API that is implemented on my website is being read by my Android application as null, thus with the aforementioned error.
I have also tried to solve the problem by doing the following:
Created a separate response class called ForgotPassRP with the same variables, because the DataRP response class is being used by other classes.
Updated the version of the retrofit that is implemented in my
build.grade(:app) from 2.7.2 to 2.9.0 and the retrofit2:converter-gson from 2.5.0 to 2.9.0.
Currently, I am still finding a solution by digging more about REST APIs on websites and Retrofit on Android, and I will implement anything new that I can learn from these. So am I missing something on my website, and Android code, or are there variables that are missing, while I am trying to do a POST method to the API that I have implemented to my website?
These are the following body of codes that I have analyzed so far that are connected to the problem (java.lang.AssertionError) that I am encountering on my Android application
The screenshot of the actual error that is being shown in the Logcat of my Android Studio:
Website:
1. APIS.php
//This is where the #POST method from my Android application API interface of the "ForgotPassword.java" is communicating with
public function forgot_password_post()
{
$response = array();
$user_info = $this->common_model->check_email($this->get_param['email'])[0];
if (!empty($user_info))
{
$this->load->helper("rendomPassword");
$info['new_password'] = get_random_password();
$updateData = array(
'user_password' => md5($info['new_password'])
);
$data_arr = array(
'email' => $user_info->user_email,
'password' => $info['new_password']
);
if ($this->common_model->update($updateData, $user_info->id, 'tbl_users')) {
$subject = $this->app_name . ' - ' . $this->lang->line('forgot_password_lbl');
$body = $this->load->view('admin/emails/forgot_password.php', $data_arr, TRUE);
if (send_email($user_info->user_email, $user_info->user_name, $subject, $body))
{
$row_info = array('success' => '1', 'msg' => $this->lang->line('password_sent_mail'));
}
else
{
$row_info = array('success' => '0', $this->lang->line('email_not_sent'));
}
}
}
else
{
$row_info = array('success' => '0', 'msg' => $this->lang->line('email_not_found'));
}
$this->set_response($row_info, REST_Controller::HTTP_OK);
}
Android Application
1. ForgotPassword.java
package com.example.mototecxecommerceapp.activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.example.mototecxecommerceapp.R;
import com.example.mototecxecommerceapp.response.DataRP;
import com.example.mototecxecommerceapp.response.ForgotPassRP;
import com.example.mototecxecommerceapp.rest.ApiClient;
import com.example.mototecxecommerceapp.rest.ApiInterface;
import com.example.mototecxecommerceapp.util.API;
import com.example.mototecxecommerceapp.util.ConstantApi;
import com.example.mototecxecommerceapp.util.Method;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.textfield.TextInputEditText;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.NotNull;
import io.github.inflationx.viewpump.ViewPumpContextWrapper;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ForgetPassword extends AppCompatActivity {
private Method method;
private TextInputEditText editText;
private ProgressDialog progressDialog;
private InputMethodManager imm;
#Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fp);
method = new Method(ForgetPassword.this);
method.forceRTLIfSupported();
progressDialog = new ProgressDialog(ForgetPassword.this);
imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
MaterialToolbar toolbar = findViewById(R.id.toolbar_fp);
toolbar.setTitle(getResources().getString(R.string.forget_password));
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
editText = findViewById(R.id.editText_fp);
MaterialButton button = findViewById(R.id.button_fp);
button.setOnClickListener(v -> {
String string_fp = editText.getText().toString();
editText.setError(null);
if (!isValidMail(string_fp) || string_fp.isEmpty()) {
editText.requestFocus();
editText.setError(getResources().getString(R.string.please_enter_email));
} else {
editText.clearFocus();
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
if (method.isNetworkAvailable()) {
forgetPassword(string_fp);
} else {
method.alertBox(getResources().getString(R.string.internet_connection));
}
}
});
}
private boolean isValidMail(String email) {
return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
}
public void forgetPassword(String sendEmail) {
progressDialog.show();
progressDialog.setMessage(getResources().getString(R.string.loading));
progressDialog.setCancelable(false);
JsonObject jsObj = (JsonObject) new Gson().toJsonTree(new API(ForgetPassword.this));
jsObj.addProperty("email", sendEmail);
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<DataRP> call = apiService.getForgotPass(API.toBase64(jsObj.toString()));
call.enqueue(new Callback<DataRP>() {
#Override
public void onResponse(#NotNull Call<DataRP> call, #NotNull Response<DataRP> response) {
try {
DataRP dataRP = response.body();
assert dataRP != null; //This is the part of the code where the java.lang.AssertionError is being thrown.
if (dataRP.getStatus().equals("1")) {
if (dataRP.getSuccess().equals("1")) {
editText.setText("");
}
method.alertBox(dataRP.getMsg());
} else {
method.alertBox(dataRP.getMessage());
}
} catch (Exception e) {
Log.d(ConstantApi.exceptionError, e.toString());
method.alertBox(getResources().getString(R.string.failed_response));
}
progressDialog.dismiss();
}
#Override
public void onFailure(#NotNull Call<DataRP> call, #NotNull Throwable t) {
// Log error here since request failed
Log.e(ConstantApi.failApi, t.toString());
progressDialog.dismiss();
method.alertBox(getResources().getString(R.string.failed_response));
}
});
}
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
2. ApiInterface.java
//This is the post method that is being sent to the forgot password API of my website.
#POST("apis/forgot_password")
#FormUrlEncoded
Call<DataRP> getForgotPass(#Field("data") String data);
3. DataRP.java
package com.example.mototecxecommerceapp.response;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
//This is the response from the #POST method.
public class DataRP implements Serializable {
#SerializedName("status")
private String status;
#SerializedName("message")
private String message;
#SerializedName("success")
private String success;
#SerializedName("msg")
private String msg;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getSuccess() {
return success;
}
public void setSuccess(String success) {
this.success = success;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
I am also including the screenshot of the API logs that are being stored in the database that I have integrated into my website. This part is what seems to be the response of the "apis/forgot_password", whenever a post method that is thrown by my Android application is executed.
The SQL database of my website showing the logs related to "apis/forgotpassword"
This is also my first time asking a question in StackOverflow. So please bear with any "rookie mistakes" with the format/structure of the question that I have posted :)
In the android application development most used Retrofit2 Retrofit2 Documention
Then Generate Response Model Class (Call API using Postman). Create a Response Model with JSON
Source type:> JSON. Annotation style:>Gson.
Use this code in the "onResponse" method section.
if (response.isSuccessful()) {
if (response.body() != null) {
DataRP dataRp=response.body();
//code statement... } }
My weather app uses Openweathermap API. But i can only get forecast for the city I put in the code.
I want to add an option so the user types his city name and get the weather forecast for it.
I've added an EditText to the layout but don't know how to get the data from it and use as the city name input.
Here is my code:
package com.hamed.myapplication;
import android.content.Context;
import android.util.Log;
import com.android.volley.DefaultRetryPolicy;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.hamed.myapplication.view.dataModel.WeatherInfo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by Hamed on 8/20/2017.
*/
public class ApiService {
private static final String TAG = "ApiService";
private Context context;
public ApiService (Context context){
this.context=context;
}
public void getCurrentWeather(final OnWeatherInfoRecieved onWeatherInfoRecieved, String cityName){
JsonObjectRequest request=new JsonObjectRequest(Request.Method.GET,
"http://api.openweathermap.org/data/2.5/weather?q=ahvaz&apikey=01a477912e47daf2010808cc62015829",
null, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i(TAG, "onResponse: "+response.toString());
onWeatherInfoRecieved.onRecieved(parseResponseToWeatherInfo(response));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.e(TAG, "onErrorResponse: "+error.toString());
onWeatherInfoRecieved.onRecieved(null);
}
});
request.setRetryPolicy(new DefaultRetryPolicy(8000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
RequestQueue requestQueue= Volley.newRequestQueue(context);
requestQueue.add(request);
}
private WeatherInfo parseResponseToWeatherInfo(JSONObject response){
WeatherInfo weatherInfo= new WeatherInfo();
try {
JSONArray weatherJsonArray= response.getJSONArray("weather");
JSONObject weatherJsonObject= weatherJsonArray.getJSONObject(0);
weatherInfo.setWeatherName(weatherJsonObject.getString("main"));
weatherInfo.setWeatherName(weatherJsonObject.getString("description"));
JSONObject mainJsonObject=response.getJSONObject("main");
weatherInfo.setWeatherTemperature((float)mainJsonObject.getDouble("temp"));
weatherInfo.setHumidity(mainJsonObject.getInt("humidity"));
weatherInfo.setPressure(mainJsonObject.getInt("pressure"));
weatherInfo.setMinTemperature((float)mainJsonObject.getDouble("temp_min"));
weatherInfo.setMaxTemperature((float)mainJsonObject.getDouble("temp_max"));
JSONObject windJsonObject=response.getJSONObject("wind");
weatherInfo.setWindSpeed((float)windJsonObject.getDouble("speed"));
weatherInfo.setWindDegree((float)windJsonObject.getDouble("deg"));
return weatherInfo;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
public interface OnWeatherInfoRecieved {
void onRecieved(WeatherInfo weatherInfo);
}
}
Edit:
My app has a button to request data from server. I want the user to type his city name in the EditText and the API address use that city name in it...
Someone told me I have to use the EditText value as QueryString and give it to the API.
Does anyone know how to do this?
To get value from EditText:
EditText edit = (EditText) view.findViewById("myEditText");
String city = edit.getText().toString();
Is that what you're looking for?
To add city selection, you would have to call the remote openweathermap service and retrieve the cities.
For Openweathermap API, you can refer to this tutorial, which explains in detail how to add the city search option in your weather app. The final source code for it is on Github here. You can take a look in the XML file and the Java Class specifically for the city selection in the sample application source code.
Ive been doing this tutorial using Android Studio IDE.
The problem I have is that the tutorial was done with older libraries of gson and retrofit 1.8.0...
I was following along well with retrofit2.0-beta3 until I came upon this error that I cant seem to resolve..
It has something to do with this line...(this line is in my MainActivity.Java under onCreate())
SCService scService = SoundCloud.getService();
scService.getRecentTracks(new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()), new Callback<List<Track>>() {
#Override
public void onResponse(Response<List<Track>> tracks) {
Log.d("TAG", "ONRESPONSE() - -- - some else wrong");
// response.isSuccess() is true if the response code is 2xx
if (tracks.isSuccess()) {
Log.d("TAG", "ONRESPONSE()_isSuccess? - -- - some else wrong");
List<Track> track = tracks.body();
loadTracks(track);
} else {
Log.d("TAG", "some else wrong");
}
}
#Override
public void onFailure(Throwable t) {
// handle execution failures like no internet connectivity
Log.d("Error", t.getMessage());
}
});
so I think that the problem starts with scService Interface..
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.http.GET;
import retrofit2.http.Query;
interface SCService {
#GET("tracks?client_id=" + Config.CLIENT_ID)
public void getRecentTracks(#Query("created_at[from]") String date, Callback<List<Track>> cb);
}
Here is my Soundcloud class....
import retrofit2.Retrofit;
import retrofit2.Retrofit;
public class SoundCloud {
private static final Retrofit REST_ADAPTER = new Retrofit.Builder().baseUrl(Config.API_URL).build();
private static final SCService SERVICE = REST_ADAPTER.create(SCService.class);
public static SCService getService() {
return SERVICE;
}
}
This is the Config class didnt think it would be needed...
public class Config {
public static final String CLIENT_ID = "c85f6828ae5eaf5981937ead09ef1b45";
public static final String API_URL = "https://api.soundcloud.com/";
}
I have been at this the whole day, Any help would be much appreciated..
It could be few things, but most likely the problem is that Gson converter is no longer automatically registered with retrofit and thus your code doesn't know how to get you object from Json. I.e. in retrofit2 you need to register Gson like:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://api.nuuneoi.com/base/")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
Take a look at this article: Retrofit 2 changes, Custom Gson Object (in the middle of the page)
I'm using Volley in an Android App to fetch data from the Misfit API (http://build.misfit.com). I tried to construct an intermittent activity, after someone logged in, to get all the data from the API. In that activity, I perform a JsonObject GET request, that should give me some information about the user of the app. Here's the code so far:
package com.iss_fitness.myapplication;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.Volley;
import org.json.JSONObject;
import java.util.HashMap;
import java.util.Map;
import learn2crack.weboauth2.R;
public class LoadingScreenActivity extends Activity {
//Introduce an delay
private final int WAIT_TIME = 500;
private static final String QUERY_URL = "https://api.misfitwearables.com/move/resource/v1/user/me/profile";
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
System.out.println("LoadingScreenActivity screen started");
setContentView(R.layout.loading_screen);
findViewById(R.id.mainSpinner1).setVisibility(View.VISIBLE);
// Instantiate the RequestQueue.
final RequestQueue queue = Volley.newRequestQueue(this);
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
executeJson();
System.out.println("Going to Profile Data");
/* Create an Intent that will start the ProfileData-Activity. */
Intent mainIntent = new Intent(LoadingScreenActivity.this, DataView.class);
LoadingScreenActivity.this.startActivity(mainIntent);
LoadingScreenActivity.this.finish();
}
}, WAIT_TIME);
}
private Response.ErrorListener createRequestErrorListener() {
return new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
System.out.println(error);
}
};
}
private void executeJson() {
SharedPreferences prefs = this.getSharedPreferences("AppPref", MODE_PRIVATE);
final String token = prefs.getString("token", null);
RequestQueue queue = Volley.newRequestQueue(this);
Map<String, String> params = new HashMap<String, String>();
System.out.println(token);
params.put("access_token", token);
CustomRequest jsonRequest = new CustomRequest(Request.Method.GET, QUERY_URL, params,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
System.out.println(response);
}
}, this.createRequestErrorListener());
System.out.println(jsonRequest);
queue.add(jsonRequest);
}
}
I'm quite new to Android development, so please bear with me, I'll try to describe the code. I've implemented a help class as suggested for JsonObjectRequest, as, as I understood, you can't override the getparams method when defining a request locally. the executeJson() method is the interesting one: I get the user access token from my SharedPreferences (Where it's correctly stored), put that in a String Map and give that to the CustomRequest, where, inside the help class, it gets thrown into a getparams method that simply returns the params. The responselistener sadly never gets called, as the errorlistener reports the following:
com.android.volley.NoConnectionError: java.io.IOException: No authentication challenges found
According to the API reference of Misfit, that should work.
Now, I know that a GET request requires "headers" and not "params" but does that make any difference?
Okay, I found a solution. The helper class contained an overriding getparams method, but no getheaders method. GET request requires getheaders, post requires getparams.
I am new to Android testing. All I am trying now is new Espresso with Junit4. the thing I go till now is Espresso is for ui testing and with junit we can do logical testing. So I am trying Junit to test my retrofit code:
protected String signIn(String emailNumber, String password) {
RestAdapter restAdapter = new RestAdapter.Builder().setEndpoint(Constants.API_URL).build();
RetroInterface retroInterface = restAdapter.create(RetroInterface.class);
retroInterface.signIn(emailNumber, password, new Callback<SignInPojo>() {
#Override
public void success(SignInPojo signInPojo, Response response) {
if (signInPojo.getError()) {
Snackbar.with(getApplicationContext()).text(signInPojo.getMessage())
.textColor(getResources().getColor(R.color.red_400)).show(SignInActivity.this);
result = "successerror";
} else {
Log.d("Json", signInPojo.getName());
result = "Successfully Signed In";
editor = sharedPreferences.edit();
editor.putBoolean(Constants.IS_LOGGED_IN, true);
editor.apply();
startActivity(new Intent(getApplicationContext(), LenderActivity.class));
finish();
}
}
#Override
public void failure(RetrofitError error) {
Log.d("RetroError", error.toString());
Log.d("RetroUrl", error.getUrl());
result = "failed";
}
});
return result;
}
with these test Class:
SignInActivityJunit.java
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
#RunWith(AndroidJUnit4.class)
#SmallTest
public class SignInActivityJunit extends ActivityInstrumentationTestCase2<SignInActivity>{
private SignInActivity signInActivity;
public SignInActivityJunit() {
super(SignInActivity.class);
}
#Before
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
signInActivity = getActivity();
}
#Test
public void checkSignIn_Success() {
String result = signInActivity.signIn("99929992", "aaaaaaaa");
assertThat(result, is(equalTo("success")));
}#Test
public void checkSignIn_SuccessButError() {
String result = signInActivity.signIn("99929992", "aaaaaaaa");
assertThat(result, is(equalTo("successerror")));
}#Test
public void checkSignIn_Fail() {
String result = signInActivity.signIn("99929992", "aaaaaaaa");
assertThat(result, is(equalTo("success")));
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
}
}
Now these all cases failed because on debugging I saw that they are not waiting for the network to return call(As per my guess). They are skipping success and failure methods.
So the question is.. how to make unit test wait till retrofit returns the request. Or is there any other efficient way to test these network connectivity.
Thank you
This won't answer your question, but I think a more correct way of testing web services would be to mock the server and request, or to actually test the UI with espresso.
In first case, with jUnit, you don't create an actual request, but rather a mocking one that will return a predifined result (the result could be read from a file). Here you could test that the conversion of response to your model classes is successful, if you have any.
In the second case, with Espresso, test the actual thing on device, like open LoginActivity -> retrieve the login/username fields -> type text -> click on Login button. And as expected result here you could put some controls from the main activity (the one that redirects you after a successful login)