I'm having problems when I want to generate a long shareable url to a file with Dropbox SDK for Android. I mean, I have not found a way to create that url.
For example, I have a file called profile_image.jpg in app folder. I upload the file with this code (like Dropbox example):
public String subirImagenDropbox(File file) {
AndroidAuthSession sesion = buildSession(); //Like the Dropbox Example
DropboxAPI<AndroidAuthSession> mApi = new DropboxAPI<AndroidAuthSession>(sesion);
checkAppKey();
try {
FileInputStream fis = new FileInputStream(file);
String name = file.getName();
mRequest = mApi.putFileOverwriteRequest("/empleados/img_perfil/" + name,
fis,
file.length(),
new ProgressListener() {
#Override
public long progressInterval() {
return 100;
}
#Override
public void onProgress(long bytes, long total) {
System.err.println(bytes + " bytes de " + total);
}
});
if (mRequest != null) {
DropboxAPI.Entry upload = mRequest.upload(); //Here upload to Dropbox
DropboxAPI.DropboxLink share = mApi.share(upload.path); //Generate short shareable URL. Expire in 31 days
System.err.println("URL: " + share.url); //Print in LogCat for debug purpose
}
}
//... A lot catchs ...
return ""; //Return the long shareable URL
}
This code upload the file perfectly, but the shareable url is like this:
http://db.tt/abcd123
and I want (I added ?dl=1):
https://www.dropbox.com/s/abcdefghi1234567/profile_image.jpg?dl=1
(I added ?dl=1).
I did it with Java SDK (dbxClient.createShareableUrl(metadata.path)) but in Android is different. I hope someone can help me with this minor inconvenience.
Thanks!
Related
Since Digital Ocean Spaces API is compatible with AWS SDK, how to upload images to Digital Ocean Spaces programmatically using AWS SDK for Android?
Add sdk to your build.gradle in your android studio project:
compile 'com.amazonaws:aws-android-sdk-core:2.6.9'
compile 'com.amazonaws:aws-android-sdk-s3:2.6.9'
compile 'com.amazonaws:aws-android-sdk-ddb:2.6.9'
Add the following service in your manifest file:
<service android:name="com.amazonaws.mobileconnectors.s3.transferutility.TransferService"
android:enabled="true" />
Basic steps:
1.You first create AWS Credentials for accessing S3 using BasicAWSCredentails class
2.Pass AWS Credentials to AmazonS3 instance
3.You then pass AmazonS3 object to TransferUtility class
4.You assign your BucketName, FileName and FileObject(which is to be transefer) to TransferObserver class
5.Finally you track your transfer details using setTransferListener of TransferObserver class
Code (tested and worked):
AmazonS3Client s3;
BasicAWSCredentials credentials;
TransferUtility transferUtility;
final TransferObserver observer;
String key = "YOUR_SPACES_KEY";
String secret = "YOUR_SPACES_SECRET_KEY";
credentials = new BasicAWSCredentials(key, secret);
s3 = new AmazonS3Client(credentials);
s3.setEndpoint("https://BUCKET_NAME.nyc3.digitaloceanspaces.com/DIRECTORY_IF_NEEDED");
transferUtility = new TransferUtility(s3, activity);
CannedAccessControlList filePermission = CannedAccessControlList.PublicRead;
observer = transferUtility.upload(
"", //empty bucket name, included in endpoint
"FILE_NAME.PNG",
new File(), //a File object that you want to upload
filePermission
);
observer.setTransferListener(new TransferListener() {
#Override
public void onStateChanged(int id, TransferState state) {
if (state.COMPLETED.equals(observer.getState())) {
Toast.makeText(activity, "Space upload completed !!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onProgressChanged(int id, long bytesCurrent, long bytesTotal) {
}
#Override
public void onError(int id, Exception ex) {
Toast.makeText(activity, "Space upload error: " + ex.getMessage(), Toast.LENGTH_SHORT).show();
}
});
Reference from: http://yasirameen.com/2016/10/uploading-file-to-amazon-s3/
You can try to read this article:
Send Image from Java to DigitalOcean Space (Bucket) using AWS SDK
I wrote it because I couldn't find any good example for Java. You can apply my knowledge in Android just as well. The idea is that you convert the image to base64-encoded byte array and then use AWS SDK's endpoint putObject() and pass ObjectMetadata as a parameter. In this object you specify what the string represents ("image/jpg") and that's it.
public String uploadBase64ToStorage(int userid, String location, String strimage) {
AWSCredentialsProvider awscp = new AWSStaticCredentialsProvider(
new BasicAWSCredentials("DO_ACCESS_KEY", "DO_SECRET_KEY")
);
AmazonS3 space = AmazonS3ClientBuilder
.standard()
.withCredentials(awscp)
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration("BUCKET_ENDPOINT", "BUCKET_REGION")
)
.build();
byte[] byteimage = Base64.getDecoder().decode(strimage);
InputStream is = new ByteArrayInputStream(byteimage);
ObjectMetadata om = new ObjectMetadata();
om.setContentLength(byteimage.length);
om.setContentType("image/jpg");
String filepath = /somefolder/someanotherfolder/testfile.jpg";
space.putObject("BUCKET_NAME", filepath, is, om);
return space.getUrl("BUCKET_NAME", filepath).toString();
}
For full tutorial, follow article link above.
In case anyone is looking for Core Java implementation see below code,
public static String uploadToDOSpaces(InputStream uploadedInputStream, String fileName1, String bucketPath,
String ext1) {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
String bucketName = "files" + bucketPath;
String keyName = timestamp.getTime() + ext1;
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration("region.digitaloceanspaces.com", "your region"))
.withCredentials(new AWSStaticCredentialsProvider(
new BasicAWSCredentials("Access-Key", "Secret-Key")))
.build();
ObjectMetadata meta = new ObjectMetadata();
byte[] bytes = null;
try {
bytes = IOUtils.toByteArray(uploadedInputStream);
} catch (IOException e) {
}
meta.setContentLength(bytes.length);
meta.setContentDisposition("inline");
switch (ext1) {
case "txt":
meta.setContentType("text/plain");
break;
case "pdf":
meta.setContentType("application/pdf");
break;
case "jpeg":
meta.setContentType("image/jpeg");
break;
case "jpg":
meta.setContentType("image/jpeg");
break;
case "gif":
meta.setContentType("image/gif");
break;
case "png":
meta.setContentType("image/png");
break;
case "PNG":
meta.setContentType("image/png");
break;
case "mp4":
meta.setContentType("video/mp4");
break;
case "MP4":
meta.setContentType("video/mp4");
break;
}
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
s3Client.putObject(new PutObjectRequest(bucketName, keyName, byteArrayInputStream, meta)
.withCannedAcl(CannedAccessControlList.PublicRead));
java.util.Date expiration = new java.util.Date();
long msec = expiration.getTime();
msec += 1000 * 60 * 60; // 1 hour.
expiration.setTime(msec);
URL abc = s3Client.generatePresignedUrl(bucketName, keyName, expiration);
String abcurl = abc.toString();
String[] urls = abcurl.split("\\?");
return urls[0];
}
Also here are maven dependencies.
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.511</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<version>1.11.511</version>
</dependency>
Thanks and cheers..!!
I am uploading & downloading files in bucket created on Google Cloud through Project created in Android-Studio.
I am feeling that images upload and download is taking long time.
I have also checked it by enabling automatic scaling, my appengine-web.xml file looks like:
<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
<application>APP_ID</application>
<version>1</version>
<threadsafe>true</threadsafe>
<instance-class>F4_1G</instance-class>
<automatic-scaling>
<min-idle-instances>1</min-idle-instances>
<!-- ‘automatic’ is the default value. -->
<max-idle-instances>automatic</max-idle-instances>
<!-- ‘automatic’ is the default value. -->
<min-pending-latency>30ms</min-pending-latency>
<max-pending-latency>automatic</max-pending-latency>
<max-concurrent-requests>50</max-concurrent-requests>
</automatic-scaling>
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
<property name="gcm.api.key" value="gcm_key" />
</system-properties>
</appengine-web-app>
And Servlet to Upload image looks like this:
public class UploadImageServlet extends HttpServlet {
private static final Logger logger = Logger.getLogger(UploadImageServlet.class.getName());
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
ServletFileUpload upload = new ServletFileUpload();
resp.setContentType("text/plain");
FileItemIterator iterator = upload.getItemIterator(req);
ImageJson data = new ImageJson();
byte[] image = null;
byte[] imageThumbnail = null;
while (iterator.hasNext()) {
FileItemStream item = iterator.next();
InputStream stream = item.openStream();
if (item.isFormField()) {
String field = item.getFieldName();
String value = IOUtils.toString(stream);
try {
if (field.equalsIgnoreCase(SESSION_PARAM_IN_FORM)) {
data.session = value;
} else if (field.equalsIgnoreCase(USER_PARAM_IN_FORM)) {
data.user = Long.parseLong(value);
}
} catch (NumberFormatException e) {
logger.warning("Invalid " + field);
}
// user, session
} else {
logger.info("Got an uploaded file: " + item.getFieldName() + ", name = " + item.getName());
data.imageName = item.getName();
// You now have the filename (item.getName() and the
// contents (which you can read from stream). Here we just
// print them back out to the servlet output stream, but you
// will probably want to do something more interesting (for
// example, wrap them in a Blob and commit them to the
// datastore).
image = IOUtils.toByteArray(stream);
System.out.println("Creating Thumbnail...");
ImagesService imagesService = ImagesServiceFactory.getImagesService();
Image oldImage = ImagesServiceFactory.makeImage(image);
Transform resize = ImagesServiceFactory.makeResize(120, 120);
//Resize The Image using the transform created above
Image resizedImage = imagesService.applyTransform(resize, oldImage);
imageThumbnail = resizedImage.getImageData();
System.out.println("Thumbnail created!!");
}
}
resp.getWriter().write(new Gson().toJson(saveImage(data, image, imageThumbnail)));
} catch (Exception ex) {
throw new ServletException(ex);
}
}
}
You must upload and download images using Json format.
If you want to know any more, please contact me
Hope will be helpfull
Burcu Dogan wrote some example code showing how to sync a local preferences file to the user's Google Drive appfolder, found here: https://github.com/googledrive/appdatapreferences-android
I've converted this example to use the current Drive SDK, now shipping with Google Play Services.
If I update the cloud Drive file with device 1, and then run the following code on device 2, I'm getting a stale "modified" timestamp from the metadata. I'm assuming this is because the results are from a local cache of the Drive file:
Step 1. Look up the preferences file by name, with a query:
/**
* Retrieves the preferences file from the appdata folder.
* #return Retrieved preferences file or {#code null}.
* #throws IOException
*/
public DriveFile getPreferencesFile() throws IOException
{
if (mDriveFile != null)
return mDriveFile;
GoogleApiClient googleApiClient = getGoogleApiClient();
if (!googleApiClient.isConnected())
LOGW(TAG, "getPreferencesFile -- Google API not connected");
else
LOGD(TAG, "getPreferencesFile -- Google API CONNECTED");
Query query = new Query.Builder()
.addFilter(Filters.contains(SearchableField.TITLE, FILE_NAME))
.build();
DriveApi.MetadataBufferResult metadataBufferResult =
Drive.DriveApi.query(getGoogleApiClient(), query).await();
if (!metadataBufferResult.getStatus().isSuccess()) {
LOGE(TAG, "Problem while retrieving files");
return null;
}
MetadataBuffer buffer = metadataBufferResult.getMetadataBuffer();
LOGD(TAG, "Preference files found on Drive: " +
buffer.getCount());
if (buffer.getCount() == 0)
{
// return null to indicate the preference file doesn't exist
mDriveFile = null;
// create a new preferences file
// mDriveFile = insertPreferencesFile("{}");
}
else
mDriveFile = Drive.DriveApi.getFile(
getGoogleApiClient(),
buffer.get(0).getDriveId());
// Release the metadata buffer
buffer.release();
return mDriveFile;
}
Step 2. Get the metadata for the file:
// Get the metadata
DriveFile file;
DriveResource.MetadataResult result = file.getMetadata(getGoogleApiClient()).await();
Metadata metadata = result.getMetadata();
// Get the modified dates
metadata.getModifiedDate();
More curiously, after running the code below (which just lists the appdatafolder files and their content) the metadata modified date, fetched above, becomes correct!! Why???
/**
*
* Simple debug activity that lists all files currently in Drive AppFolder and their contents
*
*/
public class ActivityViewFilesInAppFolder extends BaseActivity {
private static final String TAG = "ActivityViewFilesInAppFolder";
private TextView mLogArea;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add a text view to the window
ScrollView layout = new ScrollView(this);
setContentView(layout);
mLogArea = new TextView(this);
layout.addView(mLogArea);
ApiClientAsyncTask<Void, Void, String> task = new ApiClientAsyncTask<Void, Void, String>(this) {
#Override
protected String doInBackgroundConnected(Void[] params) {
StringBuffer result = new StringBuffer();
MetadataBuffer buffer = Drive.DriveApi.getAppFolder(getGoogleApiClient())
.listChildren(getGoogleApiClient()).await().getMetadataBuffer();
result.append("found " + buffer.getCount() + " files:\n");
for (Metadata m: buffer) {
DriveId id = m.getDriveId();
DriveFile file = Drive.DriveApi.getFile(getGoogleApiClient(), id);
DriveContents contents = file.open( getGoogleApiClient(),
DriveFile.MODE_READ_ONLY, null).await().getDriveContents();
FileInputStream is = new FileInputStream(contents.getParcelFileDescriptor()
.getFileDescriptor());
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(is, Charsets.UTF_8));
String line=null; StringBuffer sb=new StringBuffer();
while ((line=bf.readLine()) != null ) {
sb.append(line);
}
contents.discard(getGoogleApiClient());
result.append("*** " + m.getTitle() + "/" + id + "/"
+ m.getFileSize() + "B:\n [" + sb.toString() + "]\n\n");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
buffer.release();
return result.toString();
}
#Override
protected void onPostExecute(String s) {
if (mLogArea != null) {
mLogArea.append(s);
Map<String, ?> values = PreferenceManager
.getDefaultSharedPreferences(ActivityViewFilesInAppFolder.this).getAll();
String localJson = new GsonBuilder().create().toJson(values);
LOGD(TAG, "Local: " + localJson);
LOGD(TAG, "File: " + s);
}
}
};
task.execute();
}
}
Is the metadata reading from a cached local copy, unless something kicks it?
Does anyone know how to force these APIs to always pull the results from the remote Drive file?
I have an answer to your question. Well 'kind of answer', and I'm sure you will not be happy with it.
I had used RESTful API in my app before switching to GDAA. And after I did, I realized that GDAA, another layer with timing delays I have no control over, is causing issues in an app that attempts to keep multiple Android devices synchronized. See SO 22980497 22382099, 22515028, 23073474 and just grep for 'requestSync'.
I was hoping that GDAA implemented some kind of GCM logic to synchronize 'behind-the-scenes'. Especially when there is the 'addChangeListener()' method that seems to be designed for that. It does not look to be the case (at least not around Sept 2014). So, I backed off to a true-and-tested scheme of using RESTful API to talk to Google Drive with DataProvider and SyncAdapter logic behind it (much like shown in the UDACITY Class here).
What I'm not happy about, is somewhat ambiguous documentation of GDAA using terms like 'synchronize' not telling us if it is 'local' of 'network' synchronization. And not answering questions like the SO 23073474 mentioned above.
It appears (and I am not a Google insider) that GDAA has been designed for apps that do not immediately synchronize between devices. Unfortunately this has not been mentioned here or here - see 1:59, costing me a lot of time and frustration.
Now the question is: Should I (we) wait until we get 'real time' synchronization from GDAA, or should we go ahead and work on home-grown GCM based sync on top of RESTful-DataProvider-SyncAdapter?
Well, I personally will start working on GCM sync and will maintain an easy-to-use miniapp that will test GDAA behavior as new versions of Google Play Services come out. I will update this answer as soon as I have the 'test miniapp' ready and up in GitHub. Sorry I did not help much with the problem itself.
Well, I just found the secret sauce to trick the new Drive API into reading metadata from the remote file instead of the local cache.
Even though reading metadata doesn't require the file to be opened, it turns out that the file needs to be opened!
So the working code to read the latest metadata from the cloud is as follows:
DriveFile file;
// Trick Google Drive into fetching the remote file
// which has the latest metadata
file.open( getGoogleApiClient(), DriveFile.MODE_READ_ONLY, null).await();
DriveResource.MetadataResult result = file.getMetadata(getGoogleApiClient()).await();
Metadata metadata = result.getMetadata();
// Get the modified date
metadata.getModifiedDate();
Question for Google -- is this working as intended? The metadata is cached unless you first open the file read_only?
I'm trying to upload multiple images to a PHP server along with a few other parameters (strings), using the POST method. I'm using Multipart method. I added 4 libraries prescribed in various solutions (apachemime, httpclient, httpmime, httpcore), but my SDK doesn't recognise MultipartEntity, displaying the error: 'cannot be resolved to a type'. I've also tried MultipartEntityBuilder, but even that's showing the same error. I basically want to upload a Bitmap Arraylist to the server & show a progress bar simultaneously.
You should post some code with the issue so we can take a look and help you.
But if you want to try something a little bit simple you can use this library, AsyncHttpClient: http://loopj.com/android-async-http/
Using this library you could post multiple files like this:
private static AsyncHttpClient clientHttp = new AsyncHttpClient();
...
RequestParams params = new RequestParams();
final String TAG_FILE = "archivo1";
final String TAG_FILE_1 = "archivo2";
final String TAG_FILE_2 = "archivo3";
final String PATH_FILE_1 = ApplicationContext.getInstance().getFilesDir().getPath() + "/" + "file1.jpg";
final String PATH_FILE_2 = ApplicationContext.getInstance().getFilesDir().getPath() + "/" + "file2.jpg";
final String PATH_FILE_3 = ApplicationContext.getInstance().getFilesDir().getPath() + "/" + "file3.jpg";
try {
params.put(TAG_FILE, PATH_FILE_1);
params.put(TAG_FILE_1, PATH_FILE_2);
params.put(TAG_FILE_2, PATH_FILE_3);
params.put(TAG_PARAM, "SOME TEXT");
}
catch(FileNotFoundException e) {
//Manage your exception
}
final int DEFAULT_TIMEOUT = 30 * 1000;
clientHttp.setTimeout(DEFAULT_TIMEOUT);
clientHttp.post("http://somereceiver.php", params, new JsonHttpResponseHandler() {
#Override
public void onSuccess(JSONObject response) {
//Do your code on success
}
#Override
public void onStart() {
// Show your progress bar
}
#Override
public void onFinish() {
// Hide your progress bar
super.onFinish();
if(PATH_FILE_1 != null) {
File tem = new File(PATH_FILE_1);
if(tem.exists()) tem.delete();
}
if(PATH_FILE_2 != null) {
File tem = new File(PATH_FILE_2);
if(tem.exists()) tem.delete();
}
if(PATH_FILE_3 != null) {
File tem = new File(PATH_FILE_3);
if(tem.exists()) tem.delete();
}
}
});
You could also use the generic response type if you dont need json, so you get a string.
Hope this helps.
I want to integrate Google drive with my app I have registered my app in Google Developers Console. I got a sample from https://github.com/googledrive/android-demos .By this i am able to create a file,folder in Google drive's root folder but the problem is I couldn't create a file or folder inside an existing folder. In such case i got a toast "Cannot find DriveId. Are you authorized to view this file?" ie I cannot get the driveID
public class CreateFolderInFolderActivity extends BaseDemoActivity {
#Override
public void onConnected(Bundle connectionHint) {
super.onConnected(connectionHint);
Drive.DriveApi.fetchDriveId(getGoogleApiClient(), EXISTING_FOLDER_ID)
.setResultCallback(idCallback);
}
final ResultCallback<DriveIdResult> idCallback = new ResultCallback<DriveIdResult>() {
#Override
public void onResult(DriveIdResult result) {
if (!result.getStatus().isSuccess()) {
showMessage(result.getStatus().toString());
showMessage("Cannot find DriveId. Are you authorized to view this file?");
return;
}
DriveFolder folder = Drive.DriveApi
.getFolder(getGoogleApiClient(), result.getDriveId());
MetadataChangeSet changeSet = new MetadataChangeSet.Builder()
.setTitle("MyNewFolder").build();
folder.createFolder(getGoogleApiClient(), changeSet)
.setResultCallback(createFolderCallback);
}
};
final ResultCallback<DriveFolderResult> createFolderCallback = new
ResultCallback<DriveFolderResult>() {
#Override
public void onResult(DriveFolderResult result) {
if (!result.getStatus().isSuccess()) {
showMessage("Problem while trying to create a folder");
return;
}
showMessage("Folder successfully created");
}
};
}
I cannot find any proper documentation for this.
Plz help me where i am going wrong or Whether I Have to include any other permissions
You can take a peek here: in the 'createTree()' method, there is a creation of folder within a folder.
There are 3 different drive ID entities in the new Google Drive Android API (GDAA)
the object of type DriveID - the one you get from methods and use in your code
a string you get from encodeToString() and pass to decodeFromString() - used to save within the app (caching for instance)
a string you get from getResourceId() and pass to fetchDriveId() - the one you see in the html address of a file.
Both 2 and 3 identifiers are strings, so they may be confused. Identifier 2 is faster when retrieving Drive ID (via decodeFromString()). Identifier 3 is slower to retrieve (via fetchDriveId()), but usefull if you need to take your ID elsewhere (Apps Script, for instance).
Please see also: SO 21800257
What is EXISTING_FOLDER_ID? If you are trying to just run the sample straight out without having made any changes, this won't work.
You need to change EXISTING_FOLDER_ID to the resource id of a folder that your app has access to. This could be a folder that your app created in the root.
first create folder using creatreeTree()
then run a search query to get id of create public static ArrayList<ContentValues> search(String prnId, String titl, String mime) {
ArrayList<ContentValues> gfs = new ArrayList<>();
if (mGOOSvc != null && mConnected) try {
// add query conditions, build query
String qryClause = "'me' in owners and ";
if (prnId != null) qryClause += "'" + prnId + "' in parents and ";
if (titl != null) qryClause += "title = '" + titl + "' and ";
if (mime != null) qryClause += "mimeType = '" + mime + "' and ";
qryClause = qryClause.substring(0, qryClause.length() - " and ".length());
Drive.Files.List qry = mGOOSvc.files().list().setQ(qryClause)
.setFields("items(id,mimeType,labels/trashed,title),nextPageToken");
String npTok = null;
if (qry != null) do {
FileList gLst = qry.execute();
if (gLst != null) {
for (File gFl : gLst.getItems()) {
if (gFl.getLabels().getTrashed()) continue;
gfs.add( UT.newCVs(gFl.getTitle(), gFl.getId(), gFl.getMimeType()));
} //else UT.lg("failed " + gFl.getTitle());
npTok = gLst.getNextPageToken();
qry.setPageToken(npTok);
}
} while (npTok != null && npTok.length() > 0); //UT.lg("found " + vlss.size());
} catch (Exception e) { UT.le(e); }
return gfs;
}
when you get folder id use this code to create folder in folder ` public static ParentReference insertFileIntoFolder(Drive service, String folderId,
String folderName) throws IOException {
// Log.e("founddd",id);
File fileMetadata = new File();
fileMetadata.setParents(Collections.singletonList(new ParentReference().setId(folderId == null ? "root" : folderId)));
fileMetadata.setTitle(folderName);
fileMetadata.setMimeType("application/vnd.google-apps.folder");
File file = mGOOSvc.files().insert(fileMetadata).execute();
System.out.println("Folder ID: " + file.getId());
strChildFolder = file.getId();
return null;
}`