JSON experimental from Android App - android

On Android I am able to upload an object Ok. But when I try to download it, I get the following error on getObject.executeMediaAndDownloadTo(out).
java.lang.IllegalArgumentException: Type must be in the 'maintype/subtype; parameter=value' format
Code is from the Google example:
Storage.Objects.Get getObject = storage.objects().get("bucket", "myObject");
if (getMetadata == true) {
getObject.setAlt("json"); // Temporary workaround.
StorageObject object = getObject.execute();
} else {
// Downloading data.
out = new ByteArrayOutputStream();
// If you're not in AppEngine, download the whole thing in one request, if possible.
// NOTE: As of right now, this will not retry on retryable failure.
// http://code.google.com/p/google-api-java-client/issues/detail?id=579
getObject.getMediaHttpDownloader().setDirectDownloadEnabled(true);
getObject.executeMediaAndDownloadTo(out);
}

Related

Google Cloud TextToSpeech : java.io.IOException: The Application Default Credentials are not available

I am trying to run the TextToSpeech code from Google Cloud TextToSpeech Service.
Curently stuck at Authentication part referring link Authenticating as a service account
Below is the Code :
public class TexttoSpeech {
/** Demonstrates using the Text-to-Speech API. */
public static void getAudio() throws Exception {
// Instantiates a client
// Below Line is Point of Error in Code
try (TextToSpeechClient textToSpeechClient = TextToSpeechClient.create()) {
// Set the text input to be synthesized
SynthesisInput input = SynthesisInput.newBuilder().setText("Hello, World!").build();
// Build the voice request, select the language code ("en-US") and the ssml voice
//gender
// ("neutral")
VoiceSelectionParams voice =
VoiceSelectionParams.newBuilder()
.setLanguageCode("en-US")
.setSsmlGender(SsmlVoiceGender.NEUTRAL)
.build();
// Select the type of audio file you want returned
AudioConfig audioConfig =
AudioConfig.newBuilder().setAudioEncoding(AudioEncoding.MP3).build();
// Perform the text-to-speech request on the text input with the selected voice parameters and
// audio file type
SynthesizeSpeechResponse response =
textToSpeechClient.synthesizeSpeech(input, voice, audioConfig);
// Get the audio contents from the response
ByteString audioContents = response.getAudioContent();
byte[] audioArray=audioContents.toByteArray();
String converted= Base64.encodeBase64String(audioArray);
playAudio(converted);
// Write the response to the output file.
try (OutputStream out = new FileOutputStream("output.mp3")) {
out.write(audioContents.toByteArray());
System.out.println("Audio content written to file \"output.mp3\"");
}
}
}
public static void playAudio(String base64EncodedString){
try
{
String url = "data:audio/mp3;base64,"+base64EncodedString;
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(url);
mediaPlayer.prepare();
mediaPlayer.start();
}
catch(Exception ex){
System.out.print(ex.getMessage());
}
}
}
But getting below error on :
java.io.IOException: The Application Default Credentials are not available. They are available
if running in Google Compute Engine. Otherwise, the environment variable
GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials.
See https://developers.google.com/accounts/docs/application-default-credentials for more
information.
Also tried Explicit credentials :
#Throws(IOException::class)
fun authExplicit() {
val projectID = "texttospeech-12345" // dummy id
// val imageUri: Uri =
Uri.fromFile(File("file:\\android_asset\\service_account_file.json"))
// val path=File(imageUri.path).absolutePath
// You can specify a credential file by providing a path to GoogleCredentials.
// Otherwise credentials are read from the GOOGLE_APPLICATION_CREDENTIALS environment
variable.
val credentials =
GoogleCredentials.fromStream(mContext.resources.openRawResource(R.raw.service_account_file))
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"))
val storage: Storage =
StorageOptions.newBuilder().setProjectId(projectID).setCredentials(credentials)
.build().service
println("Buckets:")
// Error at storage.lists()
val buckets: Page<Bucket> = storage.list()
for (bucket in buckets.iterateAll()) {
println(bucket.toString())
}
}
But on device it gives error like :
Error getting access token for service account:
Unable to resolve host "oauth2.googleapis.com": No address associated with hostname, iss:
xyz#texttospeech-12345.iam.serviceaccount.com
And on Emulator the error is :
xxxxxxxxx does not have storage.buckets.list access to the Google Cloud project.
Please let me know if you guys need something more.
Any suggestion will be appreciated
Thanks in Advance
Also if I run below command in Cloud SDK :
gcloud auth application-default login
I get this but I didnt understood what its trying to say
You can pass the credentials while creating the client connection.
TextToSpeechSettings settings = TextToSpeechSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(authExplicit("JSON FILE PATH")))
.build();
try (TextToSpeechClient textToSpeechClient = TextToSpeechClient.create(settings)) {
// ... rest of your code
}
// ... rest of your code
And
public static GoogleCredentials authExplicit(String jsonPath) throws IOException {
GoogleCredentials credentials = GoogleCredentials.fromStream(new FileInputStream(jsonPath))
.createScoped(Lists.newArrayList("https://www.googleapis.com/auth/cloud-platform"));
return credentials;
}
GoogleCredentials imported from Google Auth Library For Java OAuth2 HTTP
N.B You need to make sure you are able to fetch the JSON file in your application.

Google Drive REST API : file.getCreatedTime() returns always null

I am working with Android Quickstart for Google Drive Rest APi provided at the below link. Android Quickstart
The sample code works fine as is. However when I try to get other details from files like getCreatedTime() or GetWevViewLink() 'null' is returned. Only getName() and getId() returns values.
Google Drive REST APIs v3 would only return only certain default fields. If you need some field, you have to explicitly request it by setting it with .setFields() method.
Modify your code like this -
private List<String> getDataFromApi() throws IOException {
// Get a list of up to 10 files.
List<String> fileInfo = new ArrayList<String>();
FileList result = mService.files().list()
.setPageSize(10)
// see createdTime added to list of requested fields
.setFields("nextPageToken, files(createdTime,id,name)")
.execute();
List<File> files = result.getFiles();
if (files != null) {
for (File file : files) {
fileInfo.add(String.format("%s (%s)\n",
file.getName(), file.getId()));
}
}
return fileInfo;
}
You can read more about this behavior here https://developers.google.com/drive/v3/web/migration
Updated link https://developers.google.com/drive/api/v2/migration
Quoting from the above link -
Notable changes
Full resources are no longer returned by default. Use the fields query parameter to request specific fields to be returned. If left unspecified only a subset of commonly used fields are returned.
Accept the answer if it works for you so that others facing this issue might also get benefited.
I think you need to use the Metadata class to be able to use the getCreatedDate as indicated in Working with File and Folder Metadata.
Then try something like:
ResultCallback<MetadataResult> metadataRetrievedCallback = new
ResultCallback<MetadataResult>() {
#Override
public void onResult(MetadataResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while trying to fetch metadata");
return;
}
//show the date when file was created
Metadata metadata = result.getMetadata();
showMessage("File was created on " + metadata.getCreatedDate() );
}
}

How do I add "sheetId": XXXXXX to my Google Sheets v4 function batchupdate?

I'm almost finished with my application where I'm able to do a simple delete off of Google Spraedsheet data. However, I have not been able to find a method where I could add the sheetId and its respective GID # to the request arraylist.
private void deleteRow()
{
List<Request> requests = new ArrayList<>();
DeleteDimensionRequest deleteDimensionRequest = new DeleteDimensionRequest();
DimensionRange dimensionRange = new DimensionRange();
dimensionRange.getDimension();
dimensionRange.setStartIndex(13);
dimensionRange.setEndIndex(14);
deleteDimensionRequest.setRange(dimensionRange);
Sheets.Spreadsheets spreadsheets = null;
requests.add(new Request()
//There should be a function call or some sort for me to
//add a sheetid... if I do the updatesheets property here
//I get an error message saying that there's already a kind
//and I cannot set the id
.setDeleteDimension(deleteDimensionRequest)
);
BatchUpdateSpreadsheetRequest batchUpdateRequest = new BatchUpdateSpreadsheetRequest()
.setRequests(requests);
try
{
mService.spreadsheets().batchUpdate("SPREADSHEETID GOES HERE", batchUpdateRequest).execute();
}
catch(IOException e)
{
e.printStackTrace();
}
}
Does anyone know the strategy to add the sheet values into the request arraylist?
The function calls were actually available after creating a new constructor for DimensionRange.
Simply do:
dimensionRange.setDimension("ROWS");
dimensionRange.setSheetId(XXXXX);
to finish the JSON post request to Sheets API...

odata4j requests metadata too many times

I use the odata4j library to access a WCF Data Service.
This is how I call a Service Method from my Android code:
OQueryRequest<OEntity> l = consumer.getEntities("GetDataList")
.custom("dataId", String.format("'%s'", actualData.ID))
.orderBy("Name").skip(0).top(200);
I checked it with WireShark, and I see that every method call is preceded with 2 calls of metadata information request:
Why? Are they essential? The metadata information is quite heavy, it shouldn't request is every time (not to mention 2 times).
What should I do to prevent odata4j from requesting metadata information so many times?
I found in the source code where the 'extra' request happens (in odata4j/odata4j-core/src/main/java/org/odata4j/consumer/AbstractODataConsumer.java ):
#Override
public EdmEntitySet findEdmEntitySet(String entitySetName) {
EdmEntitySet rt = super.findEdmEntitySet(entitySetName);
if (rt == null && delegate != EdmDataServices.EMPTY) {
refreshDelegate();
rt = super.findEdmEntitySet(entitySetName);
}
return rt;
}
It seems that if the entity set can't be found, the consumer creates an extra roundtrip to the server to get the metadata again (by calling refreshDelegate()):
private void refreshDelegate() {
ODataClientRequest request = ODataClientRequest.get(AbstractODataConsumer.this.getServiceRootUri() + "$metadata");
try {
delegate = AbstractODataConsumer.this.getClient().getMetadata(request);
} catch (ODataProducerException e) {
// to support services that do not expose metadata information
delegate = EdmDataServices.EMPTY;
}
}
I don't quite understand why: maybe it assumes that the server has changed and a new version of the metadata is available so it tries again.
If it fails then it tries to find a function with the given name.
Personally I don't consider this very effective unless the server side is so volatile that it changes between calls.
So, if you have no changing metadata on the server, it is safe to remove the check for the entitySet and let it return as a null:
#Override
public EdmEntitySet findEdmEntitySet(String entitySetName) {
EdmEntitySet rt = super.findEdmEntitySet(entitySetName);
//if (rt == null && delegate != EdmDataServices.EMPTY) {
// refreshDelegate();
// rt = super.findEdmEntitySet(entitySetName);
//}
return rt; //if it is null, then the search for a function will commence
}

When uploading an image/file to server, ServiceStack throws a UnauthorizedAccessException

I used the following code from the answer to this question by #scott How do I upload an image to a ServiceStack service?
[Route("/upload","POST")]
public class UploadFileRequest
{
// Example of other properties you can send with the request
public string[] Tags { get; set; }
}
class MyFileService : Service
{
public bool Post(UploadFileRequest request)
{
// Check a file has been attached
if(Request.Files == null || Request.Files.Length == 0)
throw new HttpError(400, "Bad Request", "No file has been uploaded");
// Save the file
Request.Files[0].SaveTo(Request.Files[0].FileName);
// Maybe store the tags (or any other data in the request)
// request.Tags
return true;
}
}
Then with the JsonServiceClient in your Android app, then your simply need to do this:
var filename = "cab.jpg"; // The path of the file to upload
var client = new JsonServiceClient("http://212.175.132.168/service/api/");
using(var fileStream = File.OpenRead(filename))
{
client.PostFileWithRequest<bool>(fileStream, "cab.jpg", new UploadFileRequest { Tags = new[] { "Cab", "Taxis", "NewYork", "Yellow" }});
}
I used this with my DTO and in my Android app, but when I try to send it always fails with the following server error:
{"ResponseStatus": {"ErrorCode":"UnauthorizedAccessException","Message":"'C:\\Windows\\SysWOW64\\inetsrv\\a.png' path denied.", 'C:\Windows\SysWOW64\inetsrv\a.png' path denied.
Can anyone share Monodroid ServiceStack Image upload sample?
Thanks.
There is nothing wrong with the example code, that you have taken from my answer given here, which you used in the Monodroid client. It works on Monodroid using the ServiceStack PCL library without modification.
Monodroid:
No modification required.
var filename = "cab.jpg"; // The path of the file to upload
var client = new JsonServiceClient("http://212.175.132.168/service/api/");
using(var fileStream = File.OpenRead(filename))
{
client.PostFileWithRequest<bool>(fileStream, "cab.jpg", new UploadFileRequest { Tags = new[] { "Cab", "Taxis", "NewYork", "Yellow" }});
}
Server File Permissions Error:
The error message you get when you upload to the ServiceStack service shows that your server process does not have permission to write the file to this directory C:\Windows\SysWOW64\inetsrv.
{
"ResponseStatus":
{
"ErrorCode":"UnauthorizedAccessException",
"Message":"'C:\Windows\SysWOW64\inetsrv\a.png' path denied."
}
}
You need to update the server side service to write the file to a path which the service has permission to.
class MyFileService : Service
{
public bool Post(UploadFileRequest request)
{
// Check a file has been attached
if(Request.Files == null || Request.Files.Length == 0)
throw new HttpError(400, "Bad Request", "No file has been uploaded");
// Replace with a path you have permission to write to
var path = #"c:\temp\image.png";
// Save the file
Request.Files[0].SaveTo(path);
// Maybe store the tags (or any other data in the request)
// request.Tags
return true;
}
}
If you fix the permission error you will see it works.

Categories

Resources