Commit 57a1b936 by Kunj Gupta

UOFLMA-98: Integrate api to send attachment.

parent f9ea4e6a
......@@ -3,6 +3,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
......
......@@ -6,10 +6,12 @@ import com.vsoft.uoflservicenow.utils.Constants;
import java.util.Map;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.POST;
import retrofit2.http.Query;
import retrofit2.http.QueryMap;
......@@ -39,6 +41,14 @@ public interface CatalogueVariableApi {
// Get Reference API
@GET
Call<ResponseBody> getReference(@Url String url, @QueryMap Map<String, String> options);
// Post attachment API
@POST(Constants.URL_POST_ATTACHMENT)
Call<ResponseBody> postAttachment(@Header("Content-Type") String contentType,
@Query(Constants.URL_PARAM_TABLE_SYS_ID) String tableSysId,
@Query(Constants.URL_PARAM_TABLE_NAME) String tableName,
@Query(Constants.URL_PARAM_FILE_NAME) String fileName,
@Body RequestBody attachmentRequestBody);
}
package com.vsoft.uoflservicenow.api.listeners.post;
/**
* @since 1.0
* @author Kunj on 11/8/16
*
*/
public interface PostVariableFormApiListener {
void onDoneApiCall(String variableFromSysId);
}
......@@ -9,6 +9,7 @@ import com.google.gson.JsonParseException;
import com.vsoft.uoflservicenow.api.RestClient;
import com.vsoft.uoflservicenow.api.interfaces.CatalogueVariableApi;
import com.vsoft.uoflservicenow.api.listeners.get.GetCatalogueVariableApiListener;
import com.vsoft.uoflservicenow.api.listeners.post.PostVariableFormApiListener;
import com.vsoft.uoflservicenow.db.models.CatalogueVariable;
import com.vsoft.uoflservicenow.db.models.CatalogueVariableSet;
import com.vsoft.uoflservicenow.enums.SyncStatus;
......@@ -26,6 +27,7 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;
......@@ -166,7 +168,7 @@ public class CatalogueVariableApiManager {
}
}
public static SyncStatus submitVariableForm(String catalogueItemSysId, JSONArray catalogueJsonArray) {
public static SyncStatus submitVariableForm(String catalogueItemSysId, JSONArray catalogueJsonArray, PostVariableFormApiListener listener) {
CatalogueLog.d("submitVariableForm: " + catalogueJsonArray);
String expenseJsonString = catalogueJsonArray.toString();
final Retrofit retrofit = RestClient.getInitializedRestAdapter(Constants.API_AUTH_PARAM_USER_NAME, Constants.API_AUTH_PARAM_PASSWORD);
......@@ -175,6 +177,16 @@ public class CatalogueVariableApiManager {
//Retrofit synchronous call
Response<ResponseBody> response = call.execute();
if (response.isSuccessful()) {
try {
JSONObject jsonObject = new JSONObject(response.body().string());
JSONObject error = jsonObject.optJSONObject(Constants.RESPONSE_ERROR_OBJECT_NAME);
if (error == null) {
String resultSysId = jsonObject.getString(Constants.RESPONSE_RESULT_OBJECT_NAME);
listener.onDoneApiCall(resultSysId);
}
} catch (JSONException e) {
e.printStackTrace();
}
return SyncStatus.SUCCESS;
} else {
return SyncStatus.FAIL;
......@@ -187,4 +199,25 @@ public class CatalogueVariableApiManager {
return SyncStatus.FAIL;
}
}
public static SyncStatus postAttachment(String contentType, String tableSysId, String attachmentName, RequestBody requestBody/*String attachmentJsonString*/) {
CatalogueLog.d("postAttachment: tableSysId: " + tableSysId);
final Retrofit retrofit = RestClient.getInitializedRestAdapter(Constants.API_AUTH_PARAM_USER_NAME, Constants.API_AUTH_PARAM_PASSWORD);
Call<ResponseBody> call = retrofit.create(CatalogueVariableApi.class).postAttachment(contentType, tableSysId, CatalogueVariable.Json.TABLE_NAME_VALUE, attachmentName, requestBody);
try {
//Retrofit synchronous call
Response<ResponseBody> response = call.execute();
if (response.isSuccessful()) {
return SyncStatus.SUCCESS;
} else {
return SyncStatus.FAIL;
}
} catch (IOException e) {
CatalogueLog.e("CatalogueVariableApiManager: postAttachment: IOException: ", e);
return SyncStatus.FAIL;
} catch (NullPointerException e){
CatalogueLog.e("CatalogueVariableApiManager: postAttachment: IOException: ", e);
return SyncStatus.FAIL;
}
}
}
\ No newline at end of file
......@@ -227,7 +227,9 @@ public class CatalogueVariable {
public static class Json {
public static final String SYS_ID = "sys_id";
public static final String TYPE = "type";
public static final String ORDER = "order";
/*Variable form attachment*/
public static final String TABLE_NAME_VALUE = "sc_req_item";
}
@Override
......
package com.vsoft.uoflservicenow.ui;
import android.Manifest;
import android.app.DatePickerDialog;
import android.app.ProgressDialog;
import android.app.TimePickerDialog;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
......@@ -19,6 +33,7 @@ import android.text.method.LinkMovementMethod;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.MimeTypeMap;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.DatePicker;
......@@ -27,14 +42,17 @@ import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.Toast;
import com.google.android.gms.analytics.Tracker;
import com.vsoft.uoflservicenow.CatalogueApplication;
import com.vsoft.uoflservicenow.R;
import com.vsoft.uoflservicenow.api.listeners.get.GetCatalogueVariableApiListener;
import com.vsoft.uoflservicenow.api.listeners.get.GetVariableChoiceApiListener;
import com.vsoft.uoflservicenow.api.listeners.post.PostVariableFormApiListener;
import com.vsoft.uoflservicenow.api.managers.CatalogueVariableApiManager;
import com.vsoft.uoflservicenow.api.managers.VariableChoiceApiManager;
import com.vsoft.uoflservicenow.db.models.Catalogue;
import com.vsoft.uoflservicenow.db.models.CatalogueVariable;
import com.vsoft.uoflservicenow.db.models.CatalogueVariableSet;
import com.vsoft.uoflservicenow.db.models.Reference;
......@@ -54,12 +72,20 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import okhttp3.MediaType;
import okhttp3.RequestBody;
/**
* Created by Kunj on 11/8/16.
......@@ -76,6 +102,12 @@ public class CatalogueVariableScreen extends AppCompatActivity {
private JSONArray mJsonArray;
private CatalogueApplication mApplication;
private String mCatalogueItemSysId, mCatalogueItemDescription, mCatalogueItemShortDescription, mCatalogueItemTitle;
private File mAttachmentFile;
private Uri mAttachmentUri;
private static final int WRITE_EXTERNAL_STORAGE = 1;
private static final int FILE_SELECT_CODE = 0;
private TextView mAttachmentTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
......@@ -280,6 +312,9 @@ public class CatalogueVariableScreen extends AppCompatActivity {
controlView.setOnClickListener(dateTimeListener);
} else if (viewType == ViewType.REFERENCE) {
controlView.setOnTouchListener(referenceListener);
} else if (viewType == ViewType.UI_PAGE) {
((LinearLayout)controlView).getChildAt(0).setOnClickListener(attachmentListener);
mAttachmentTextView = (TextView)((LinearLayout)controlView).getChildAt(1);
}
/*Set bottom margin for custom view*/
......@@ -356,7 +391,7 @@ public class CatalogueVariableScreen extends AppCompatActivity {
jsonColumnValue = Util.getDateTime(Util.getDateTimeFromString(value));
}
if(viewType != ViewType.SELECT_BOX) {
if(viewType != ViewType.SELECT_BOX && viewType != ViewType.UI_PAGE) {
if (TextUtils.isEmpty(jsonColumnValue)) {
hasErrors = true;
// show error view
......@@ -484,6 +519,20 @@ public class CatalogueVariableScreen extends AppCompatActivity {
}
};
View.OnClickListener attachmentListener = new View.OnClickListener() {
@Override
public void onClick(final View v) {
int permissionCheck = ContextCompat.checkSelfPermission(CatalogueVariableScreen.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permissionCheck != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(
CatalogueVariableScreen.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE);
} else {
showFileChooser();
}
}
};
class SubmitForm extends AsyncTask<String, Void, SyncStatus> {
private ProgressDialog progressDialog;
......@@ -498,9 +547,41 @@ public class CatalogueVariableScreen extends AppCompatActivity {
@Override
protected SyncStatus doInBackground(String... params) {
return CatalogueVariableApiManager.submitVariableForm(mCatalogueItemSysId, mJsonArray);
return CatalogueVariableApiManager.submitVariableForm(mCatalogueItemSysId, mJsonArray, new PostVariableFormApiListener() {
@Override
public void onDoneApiCall(String variableFromSysId) {
if(mAttachmentFile !=null) {
String uriContentType = getMimeType(mAttachmentUri);
if(uriContentType != null) {
InputStream in = null;
try {
in = new FileInputStream(mAttachmentFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte[] buf = null;
try {
buf = new byte[in.available()];
while (in.read(buf) != -1) ;
} catch (IOException e) {
e.printStackTrace();
}
RequestBody requestBody = RequestBody.create(MediaType.parse(uriContentType), buf);
CatalogueVariableApiManager.postAttachment(uriContentType, variableFromSysId, mAttachmentFile.getName(), requestBody);
}
}
}
});
}
public String getMimeType(Uri uri) {
ContentResolver cR = getContentResolver();
MimeTypeMap mime = MimeTypeMap.getSingleton();
String type = mime.getExtensionFromMimeType(cR.getType(uri));
return cR.getType(uri);
}
@Override
protected void onPostExecute(SyncStatus syncStatus) {
super.onPostExecute(syncStatus);
......@@ -539,4 +620,215 @@ public class CatalogueVariableScreen extends AppCompatActivity {
}
return super.onOptionsItemSelected(menuItem);
}
private void showFileChooser() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
try {
startActivityForResult(
Intent.createChooser(intent, "Select a File to Upload"),
FILE_SELECT_CODE);
} catch (android.content.ActivityNotFoundException ex) {
// Potentially direct the user to the Market with a Dialog
Toast.makeText(this, "Please install a File Manager.",
Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case FILE_SELECT_CODE:
if (resultCode == RESULT_OK) {
// Get the Uri of the selected file
mAttachmentUri = data.getData();
mAttachmentFile = new File(getPath(this, mAttachmentUri));
if(mAttachmentTextView!=null) {
mAttachmentTextView.setText(mAttachmentFile.getName());
}
}
break;
}
super.onActivityResult(requestCode, resultCode, data);
}
/**
* Get a file path from a Uri. This will get the the path for Storage Access
* Framework Documents, as well as the _data field for the MediaStore and
* other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @author paulburke
*/
public static String getPath(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case WRITE_EXTERNAL_STORAGE:
// If request is cancelled, the result arrays are empty.
for (int i = 0; i < permissions.length; i++) {
if (permissions[0].equals(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showFileChooser();
} else if (!ActivityCompat.shouldShowRequestPermissionRationale(CatalogueVariableScreen.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
// user denied flagging NEVER ASK AGAIN.
showCustomSettingPermissionDialog();
}
/*Break for loop*/
break;
}
}
break;
default:
break;
}
}
private void showCustomSettingPermissionDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(String.format(getString(R.string.custom_setting_storage_permission_dialog_msg_string), getString(R.string.app_name)))
.setCancelable(false)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog alert = builder.create();
alert.show();
}
}
\ No newline at end of file
......@@ -35,6 +35,9 @@ public class Constants {
public static final String URL_PARAM_SYSPRM_DISPLAY_VALUE = "sysparm_display_value";
public static final String URL_PARAM_SYSPRM_USERNAME = "user_name";
public static final String URL_PARAM_SYSPRM_LIMIT = "sysparm_limit";
public static final String URL_PARAM_TABLE_SYS_ID = "table_sys_id";
public static final String URL_PARAM_TABLE_NAME = "table_name";
public static final String URL_PARAM_FILE_NAME = "file_name";
/**
* Debug logs
......@@ -133,6 +136,7 @@ public class Constants {
public static final String URL_GET_VARIABLE_CHOICE = API_PATH + "question_choice";
public static final String URL_POST_CATALOGUE_ITEM = "api/uno33/uofl_mobile";
public static final String URL_GET_REFERENCE = API_PATH;
public static final String URL_POST_ATTACHMENT = DOMAIN + "api/now/v1/attachment/file";
/*Request API*/
public static final String URL_GET_MYREQUEST = API_PATH + "sc_req_item";
......
......@@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.Typeface;
import android.support.v4.content.ContextCompat;
import android.text.InputType;
import android.text.TextUtils;
import android.text.method.PasswordTransformationMethod;
import android.view.Gravity;
import android.view.View;
......@@ -171,6 +172,27 @@ public class Util {
breakView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 1));
breakView.setBackgroundColor(ContextCompat.getColor(context, android.R.color.black));
return breakView;
case UI_PAGE:
LinearLayout uiPageLayout = new LinearLayout(context);
uiPageLayout.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(0,LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f);
Button attachmentButton = new Button(context);
attachmentButton.setText(R.string.variable_form_ui_page_button_label_string);
attachmentButton.setLines(1);
attachmentButton.setSingleLine(true);
attachmentButton.setEllipsize(TextUtils.TruncateAt.END);
uiPageLayout.addView(attachmentButton, layoutParams);
TextView attachmentTextView = new TextView(context);
attachmentTextView.setGravity(Gravity.CENTER);
attachmentTextView.setSingleLine(true);
attachmentTextView.setLines(1);
attachmentTextView.setEllipsize(TextUtils.TruncateAt.);
attachmentTextView.setText(R.string.variable_form_ui_page_no_selected_attachment_string);
uiPageLayout.addView(attachmentTextView, layoutParams);
return uiPageLayout;
}
return null;
}
......@@ -323,6 +345,4 @@ public class Util {
InputMethodManager imm =(InputMethodManager)context.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
}
......@@ -53,7 +53,9 @@
<string name="variable_form_misc_info_string">%1$s [add %2$s]</string>
<string name="variable_form_reference_dialog_title_string">Search \'%s\'</string>
<string name="variable_form_radio_text_string">%d</string>
<string name="variable_form_ui_page_button_label_string">Add Attachment</string>
<string name="variable_form_ui_page_no_selected_attachment_string">Not Selected</string>
<string name="custom_setting_storage_permission_dialog_msg_string">To use this feature, please go to Settings -> Apps -> %s -> Permissions and enable \'Storage\' permission</string>
<!--Catalogue Item Screen-->
<string name="no_catalogue_item_string">No Catalogue Items&#8230;</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment