Using Google Cloud Storage JSON api in android - android

I want to upload image on Google Cloud Storage from my android app. For that I searched and found that GCS JSON Api provides this feature. I did a lot of research for Android sample which demonstrates its use. On the developer site they have provided code example that only support java. I don't know how to use that API in Android. I referred this and this links but couldn't get much idea. Please guide me on how i can use this api with android app.

Ok guys so I solved it and got my images being uploaded in Cloud Storage all good.
This is how:
Note: I used the XML API it is pretty much the same.
First, you will need to download a lot of libraries.
The easiest way to do this is create a maven project and let it download all the dependencies required. From this sample project :
Sample Project
The libraries should be:
Second, you must be familiar with Cloud Storage using the api console
You must create a project, create a bucket, give the bucket permissions, etc.
You can find more details about that here
Third, once you have all those things ready it is time to start coding.
Lets say we want to upload an image:
Cloud storage works with OAuth, that means you must be an authenticated user to use the API. For that the best way is to authorize using Service Accounts. Dont worry about it, the only thing you need to do is in the API console get a service account like this:
We will use this service account on our code.
Fourth, lets write some code, lets say upload an image to cloud storage.
For this code to work you must put your key generated in step 3 in assets folder, i named it "key.p12".
I don't recommend you to do this on your production version, since you will be giving out your key.
try{
httpTransport= new com.google.api.client.http.javanet.NetHttpTransport();
//agarro la key y la convierto en un file
AssetManager am = context.getAssets();
InputStream inputStream = am.open("key.p12"); //you should not put the key in assets in prod version.
//convert key into class File. from inputstream to file. in an aux class.
File file = UserProfileImageUploadHelper.createFileFromInputStream(inputStream,context);
//Google Credentianls
GoogleCredential credential = new GoogleCredential.Builder().setTransport(httpTransport)
.setJsonFactory(JSON_FACTORY)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections.singleton(STORAGE_SCOPE))
.setServiceAccountPrivateKeyFromP12File(file)
.build();
String URI = "https://storage.googleapis.com/" + BUCKET_NAME+"/"+imagename+".jpg";
HttpRequestFactory requestFactory = httpTransport.createRequestFactory(credential);
GenericUrl url = new GenericUrl(URI);
//byte array holds the data, in this case the image i want to upload in bytes.
HttpContent contentsend = new ByteArrayContent("image/jpeg", byteArray );
HttpRequest putRequest = requestFactory.buildPutRequest(url, contentsend);
com.google.api.client.http.HttpResponse response = putRequest.execute();
String content = response.parseAsString();
Log.d("debug", "response is:"+response.getStatusCode());
Log.d("debug", "response content is:"+content);} catch (Exception e) Log.d("debug", "Error in user profile image uploading", e);}
This will upload the image to your cloud bucket.
For more info on the api check this link Cloud XML API

Firstly, You should get the below information by registering your application in the GCP console.
private final String pkcsFile = "xxx.json";//private key file
private final String bucketName = "your_gcp_bucket_name";
private final String projectId = "your_gcp_project_id";
Once you get the credentials, you should put the private key (.p12 or .json) in your assets folder. I'm using JSON format private key file. Also, you should update the image location to upload.
#RequiresApi(api = Build.VERSION_CODES.O)
public void uploadImageFile(String srcFileName, String newName) {
Storage storage = getStorage();
File file = new File(srcFileName);//Your image loaction
byte[] fileContent;
try {
fileContent = Files.readAllBytes(file.toPath());
} catch (IOException e) {
e.printStackTrace();
return;
}
if (fileContent == null || fileContent.length == 0)
return;
BlobInfo.Builder newBuilder = Blob.newBuilder(BucketInfo.of(bucketName), newName);
BlobInfo blobInfo = newBuilder.setContentType("image/png").build();
Blob blob = storage.create(blobInfo, fileContent);
String bucket = blob.getBucket();
String contentType = blob.getContentType();
Log.e("TAG", "Upload File: " + contentType);
Log.e("File ", srcFileName + " uploaded to bucket " + bucket + " as " + newName);
}
private Storage getStorage() {
InputStream credentialsStream;
Credentials credentials;
try {
credentialsStream = mContext.getAssets().open(pkcsFile);
credentials = GoogleCredentials.fromStream(credentialsStream);
} catch (IOException e) {
e.printStackTrace();
return null;
}
return StorageOptions.newBuilder()
.setProjectId(projectId).setCredentials(credentials)
.build().getService();
}

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.

How to specify Google Drive API spaces using CloudRail

I am writing an Android App to access Google Drive Photos via CloudRail service. I am able to authenticate to the Google account in question and see all my files/folders in the Google Drive, but I can't access photos from Google Photos.
While browsing through the Drive API documentation, it makes a reference to spaces, specifically 3 spaces are defined: drive, photos and allDataFolder.
Where do I specify the spaces that I am interested in? But default, the drive space is being accessed. Even though, I specifically specified scope for photos:
https://www.googleapis.com/auth/drive.photos.readonly
And when Google Authentication pages opens in the mobile browser, it states that my app wants to gain access to the user's Google Photos and I grant this access. But when calling CloudRail service to get children, no photos are visible
`googledriveChildren = mGoogledriveService.getChildren("/"); // returns goole drive top level files/folders
`googledriveChildren = mGoogledriveService.getChildren("/photos"); // generates a NotFoundException
I have already been down this path and achieved the integration - with the help/guidance from the folks at Cloudrail. You should note that my integration is limited to reading/downloading from Google Photos. I have not found any way to write/upload. Nor have I found any way of reading the album structure that can be set up in Google Photos.
First, you need to include the scope for Google Photos. I did this as follows:
public static final String GOOGLE_PHOTOS_SCOPE = "https://www.googleapis.com/auth/drive.photos.readonly";
private final AtomicReference<CloudStorage> googlephotos = new AtomicReference<>();
List<String> scope = new ArrayList<>();
scope.add(My_Constants.GOOGLE_PHOTOS_SCOPE);
googlephotos.set(new GoogleDrive(context, google_client_id, "", Get.GetString(R.string.google_redirect_uri),
Get.GetString(R.string.google_authentication_state), scope));
((GoogleDrive) googlephotos.get()).useAdvancedAuthentication();
You then need to build a Cloudrail advancedRequest to download whatever data you want. I download the metadata I require as follows:
CloudStrorage service = googlephotos.get();
private void searchForGooglePhotos(final CloudStorage service) throws Throwable {
GoogleDrive google_drive = (GoogleDrive) service;
boolean more = true;
String pageToken = null;
while (more) {
StringBuilder builder = new StringBuilder();
String query = URLEncoder.encode("mimeType='image/jpeg' and trashed = false", "utf-8");
builder.append("/files?spaces=photos");
if (pageToken != null) {
builder.append("&pageToken=");
builder.append(pageToken);
}
builder.append("&q=");
builder.append(query);
builder.append("&fields=nextPageToken,files(id,name,modifiedTime,description,size," +
"imageMediaMetadata(height,rotation,width,time))");
AdvancedRequestSpecification specification = new AdvancedRequestSpecification(builder.toString());
AdvancedRequestResponse response = google_drive.advancedRequest(specification);
#SuppressWarnings("unchecked")
Map<String, Object> resultObjectMap = (Map<String, Object>) response.getBodyJsonParsed();
pageToken = (String) resultObjectMap.get("nextPageToken");
#SuppressWarnings("unchecked")
ArrayList<Map<String, Object>> filesObjectMap = ((ArrayList<Map<String, Object>>) resultObjectMap.get("files"));
for (Map<String, Object> fileObjectMap : filesObjectMap) {
// process downloaded files
}
more = (pageToken != null);
}
}
Subsequently in my app I use Glide to download the photos themselves when required. In the Glide DataFetcher I obtain the inputStream using:
if (model.getSourceRecord().isTypeGooglePhotos()) {
AdvancedRequestSpecification specification;
AdvancedRequestResponse response;
if (model.getIsThumbnail()) {
specification = new AdvancedRequestSpecification("/files" + model.getSourceId() +
"?spaces=photos&fields=thumbnailLink");
response = ((GoogleDrive) service).advancedRequest(specification);
#SuppressWarnings("unchecked")
Map<String, Object> parsed = (Map<String, Object>) response.getBodyJsonParsed();
String link = (String) parsed.get("thumbnailLink");
specification = new AdvancedRequestSpecification(link);
specification.disableBaseUrl();
} else {
specification = new AdvancedRequestSpecification("/files" + model.getSourceId() + "?spaces=photos&alt=media");
}
response = ((GoogleDrive) service).advancedRequest(specification);
input_stream = response.getBodyAsStream();
} else {
if (model.getIsThumbnail()) {
input_stream = service.getThumbnail(model.getSourceId());
} else {
input_stream = service.download(model.getSourceId());
}
}
Here, "model" contains various info associated with each photo. The sourceId comes from the "id" downloaded:
String source_id = java.io.File.separator + fileObjectMap.get("id");
I hope this helps.
Would anyone arriving at this question / response please note that, as of mid Jan 2018, Google have "sunset" (sic) the photos space (spaces=photos above). This means that the above solution no longer works.
On the Google REST API documentation: "The photos space will sunset in early January 2018. Your users can continue to access Google Photos via the drive space by enabling the Google Photos folder in My Drive in the Drive client settings"
Ugh!

Dropbox API on Android - Using Token to download file from Apps folder

I generated an access token to be able to make API calls for my own account without going through the authorization flow. I found this Dropbox files Get API but I don't know how to use it.
I tried this code, but it doesn't seem to work:
// Authentication with Token
AppKeyPair appKeys = new AppKeyPair(APP_KEY, APP_SECRET);
AndroidAuthSession session = new AndroidAuthSession(appKeys);
mDBApi = new DropboxAPI<AndroidAuthSession>(session);
mDBApi.getSession().setOAuth2AccessToken(ACCESS_TOKEN);
// Upload a file to Apps folder
File file = new File("working-draft.txt");
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
DropboxAPI.Entry response = mDBApi.putFile("/magnum-opus.txt", inputStream,
file.length(), null, null);
Log.i("DbExampleLog", "The uploaded file's rev is: " + response.rev);
} catch (Exception e) {
e.printStackTrace();
}
How can I upload and download directly to the Apps folder using the token key?
Also is there a way to print the list of all the files in my Apps folder?
The docs are pretty poor. I found the following examples on Github which helped me:
https://github.com/dropbox/dropbox-sdk-java/tree/master/examples/android/src/main/java/com/dropbox/core/examples/android
In gradle
compile 'com.dropbox.core:dropbox-core-sdk:3.0.2' or whatever is the latest
The key and secret are written into a JSON file + there's an entry you need to add into the manifest with the app key. Just follow the example which shows placeholders.
Once you've done the handshake and got the access token back
DbxRequestConfig requestConfig = DbxRequestConfig.newBuilder("your identifier")
.withHttpRequestor(new
OkHttp3Requestor(OkHttp3Requestor.defaultOkHttpClient()))
.build();
dbxClient = new DbxClientV2(requestConfig, accessToken);
dbxClient.files().[operation e.g. upload\download\file listing]

Android and AWS S3

i am creating an Android App within AWS mobile Hub, i would like to do know is it possible when a user Signs up to my Application that an S3-Bucket or even a Folder within an S3 bucket is created only for that user account ?
Yes, you can use PutObjectRequest(bucketName, keyName, file) to achieve your use case.
Create S3 folder
With AWS S3 Java SDK , just add "/" at the end of the key name, it will create empty folder.
var folderKey = key + "/"; //end the key name with "/"
Sample code:
final InputStream im = new InputStream() {
#Override
public int read() throws IOException {
return -1;
}
};
final ObjectMetadata om = new ObjectMetadata();
om.setContentLength(0L);
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, im, om);
s3.putObject(putObjectRequest);

Create spreadsheet using data from local db

I want to create a spreadsheet using the data stored in the local db. I have 5 columns and data in them. I want to create a spreadsheet having the same columns and data. I have tried using sheets api but I do not understand how to create one taking data from db
This is my code for fetching data from spreadsheet
private List<String> getDataFromApi() throws IOException {
String sheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms";
String range = "Class Data!A2:E";
List<String> results = new ArrayList<String>();
ValueRange response = this.mService.spreadsheets().values()
.get(sheetId, range)
.execute();
List<List<Object>> values = response.getValues();
if (values != null) {
results.add("Name, Major");
for (List row : values) {
results.add(row.get(0) + ", " + row.get(4));
}
}
return results;
}
This is my sheet
https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
I did some research and found out that we can edit a spreadsheet using drive api but I am not able to find out how. I have implemented drive api and can create and edit files though
Please help
You need to use Google Sheets API, the Google Sheets API v3 (formerly called the Google Spreadsheets API) lets you develop client applications that read and modify worksheets and data in Google Sheets. To fulfill the equivalent functionality of original Sheets+Docs combination, you should use Drive API to perform file manipulations such as search/move/creation/deletion.
In addition to the scopes for Drive API, add the following scope to your grant:
https://spreadsheets.google.com/feeds
If you're using GData client library and Google OAuth client library, it will be quite easy to setup both services after OAuth 2.0 authorization.
// Acquire clientId, clientSecret and refreshToken
...
// Create shared credential
GoogleCredential credential = new GoogleCredential.Builder()
.setClientSecrets(clientId, clientSecret)
.setJsonFactory(jsonFactory)
.setTransport(transport)
.build().setRefreshToken(refreshToken);
// Setup both servives
Drive driveService = new Drive.Builder(transport, jsonFactory, credential).build();
SpreadsheetService sheetService = new SpreadsheetService(...);
sheetService.setOAuth2Credentials(credential); // only provided in newer releases
sheetService.useSsl();
Resource IDs in both APIs are identical, so you can search id of some file with Drive API methods and access worksheets in the file with Sheets API methods.
File file = driveService.files().get().setFields(...).execute();
String feedUrl = "https://spreadsheets.google.com/feeds/worksheets/"
+ file.getId + "/private/full";
WorksheetFeed feed = sheetService.getFeed(feedUrl, WorksheetFeed.class);

Categories

Resources