[Huawei Developers] XDARoni:
Managing and Searching for Files

Use Case

File management is a core capability of HUAWEI Drive Kit. It enables users to conveniently manage and edit files in Drive , including creating, listing, copying, modifying, deleting, recycling, and searching for files.

Development Procedure

Step 1 Call the Drive.Builder.build API to create the Drive object.

private Drive buildDrive() {
Drive service = new Drive.Builder(CredentialManager.getInstance().getCredential(), context).build();
return service;
}

Step 2 Call the Files APIs.

NOTE：

Constants used in the sample code:

private static final int DIRECT_UPLOAD_MAX_SIZE = 20 * 1024 * 1024;

private static final int DIRECT_DOWNLOAD_MAX_SIZE = 20 * 1024 * 1024;

Call the Files.create API to create a folder.

/**
* Create a folder.
*/
private File createDirectory() {
File directory = null;
try {
Drive drive = buildDrive();
Map<String, String> appProperties = new HashMap<>();
appProperties.put("appProperties", "property");
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS");
String dirName = formatter.format(new Date());
File file = new File();
file.setFileName(dirName)
.setAppSettings(appProperties)
.setMimeType("application/vnd.huawei-apps.folder");
directory = drive.files().create(file).execute();
} catch (Exception e) {
Logger.e(TAG, "createDirectory error: " + e.toString());
}
return directory;
}

Call the Files.create API to create a file. The are two methods for uploading a file: direct upload and resumable upload. The direct upload method allows a file of up to 20 MB to be uploaded while the resumable upload method does not have such a limit. The direct upload method is recommended for files smaller than 5 MB and the resumable upload method for files larger than 5 MB.

Method 1: Directly upload the file.

/**
* Upload a file. This method supports resumable upload.
* (The upload operation resumes after it is interrupted by a communication failure, for example, network interruption.)
*
* @param filePath File path.
* @param parentId ID of the folder to which the file is to be uploaded.
* @param thumbnailImageBuffer Thumbnail data.
* @param thumbnailMimeType MIME type of the thumbnail.
*/
private void createFile(String filePath, String parentId, byte[] thumbnailImageBuffer, String thumbnailMimeType) {
try {
if (filePath == null) {
Logger.e(TAG, "createFile error, filePath is null.");
return;
}
java.io.File file = new java.io.File(filePath);
FileContent fileContent = new FileContent(null, file);
// Set thumbnail data.
File.ContentExtras contentExtras = new File.ContentExtras();
File.ContentExtras.Thumbnail thumbnail = new File.ContentExtras.Thumbnail();
thumbnail.setContent(Base64.encodeBase64String(thumbnailImageBuffer));
thumbnail.setMimeType(thumbnailMimeType);
contentExtras.setThumbnail(thumbnail);
File content = new File()
.setFileName(file.getName())
.setParentFolder(Collections.singletonList(parentId))
.setContentExtras(contentExtras);
Drive drive = buildDrive();
Drive.Files.Create request = drive.files().create(content, fileContent);
boolean isDirectUpload = false;
// Directly upload the file if it is smaller than 20 MB.
if (file.length() < DIRECT_UPLOAD_MAX_SIZE) {
isDirectUpload = true;
}
// Set the upload mode. By default, resumable upload is used. If the file is smaller than 20 MB, set this parameter to true.
request.getMediaHttpUploader().setDirectUploadEnabled(isDirectUpload);
request.execute();
} catch (Exception e) {
Logger.e(TAG, "createFile exception: " + filePath + e.toString());
}
}

Method 2: Upload the file using InputStream.

/**
* Upload the file using InputStream.
*
* @param inputStream Input stream, from which file data is read.
* @param parentId ID of the folder to which the file is to be uploaded.
* @param mimeType MIME type, for example, image (jpeg) and video (mp4).
* @param inputStreamLength Stream length.
*/
private void createFile(InputStream inputStream, String parentId, String mimeType, int inputStreamLength) {
try {
InputStreamContent streamContent = new InputStreamContent(mimeType, inputStream);
streamContent.setLength(inputStreamLength);
File content = new File()
.setFileName("video.mp4")
.setParentFolder(Collections.singletonList(parentId));
Drive drive = buildDrive();
drive.files().create(content, streamContent).execute();
} catch (Exception e) {
Logger.e(TAG, "createFile exception: " + e.toString());
}
}

Call the Files.copy API to copy the file.

/**
* Copy the file to the designated folder.
*
* @param file File to be copied.
* @param dstDir Designated folder.
*/
private void copyFile(File file, ArrayList<String> dstDir) {
try {
File copyFile = new File();
if (file == null || file.getFileName() == null ||dstDir == null) {
Log.e(TAG, "copyFile arguments error");
sendHandleMessage(R.id.drive_files_button_copy, FAIL);
return;
}
SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd_HHmmss");
String suffix = formatter.format(new Date());
copyFile.setFileName(file.getFileName() + "_copy" + "_" + suffix);
copyFile.setDescription("copyFile");
copyFile.setParentFolder(dstDir);
copyFile.setFavorite(true);
copyFile.setEditedTime(new DateTime(System.currentTimeMillis()));
Drive drive = buildDrive();
Drive.Files.Copy copyFileReq = drive.files().copy(file.getId(), copyFile);
copyFileReq.setFields("*");
File result = copyFileReq.execute();
} catch (IOException ex) {
Log.e(TAG, "copyFile error: " + ex.toString());
}
}

Call the Files.update API to modify the metadata of the file or folder.

/**
* Modify the file or folder. The value of MIMEType indicates whether it is a file or a folder.
*
* @param file File or folder to be modified.
*/
private void updateFile(File file) {
try {
if (file == null) {
Logger.e(TAG, "updateFile error, need to create file.");
return;
}
Drive drive = buildDrive();
File updateFile = new File();
updateFile.setFileName(file.getFileName() +"_update")
.setMimeType("application/vnd.huawei-apps.folder")
.setDescription("update folder")
.setFavorite(true);
drive.files().update(file.getId(), updateFile).execute();
} catch (Exception e) {
Logger.e(TAG, "updateFile error: " + e.toString());
}
}

Call the Files.update API to modify the metadata or content of the file.

/**
* Modify the file.
*
* @param oldFile File to be modified.
* @param newFilePath Path storing the modified file.
*/
private void updateFile(File oldFile, String newFilePath) {
try {
if (oldFile == null || TextUtils.isEmpty(newFilePath)) {
Logger.e(TAG, "updateFile error, need to create file.");
return;
}
java.io.File sourceFile = new java.io.File(newFilePath);
FileContent fileContent = new FileContent(null, sourceFile);
File updateFile = new File();
updateFile.setFileName(oldFile.getFileName() + "_update")
.setDescription("update folder")
.setFavorite(true);
Drive drive = buildDrive();
Drive.Files.Update update = drive.files().update(oldFile.getId(), updateFile, fileContent);
boolean isDirectUpload = false;
// Directly upload the file if it is smaller than 20 MB.
if (sourceFile.length() < DIRECT_UPLOAD_MAX_SIZE) {
isDirectUpload = true;
}
// Set the upload mode. By default, resumable upload is used. If the file is smaller than 20 MB, set this parameter to true.
update.getMediaHttpUploader().setDirectUploadEnabled(isDirectUpload);
update.execute();
} catch (Exception e) {
Logger.e(TAG, "updateFile error: " + e.toString());
}
}

Call the Files.delete API to permanently deletes a file or folder.

/**
* Permanently deletes a file or folder.
*
* @param file File or folder to be deleted.
*/
private void deleteFile(File file) {
try {
Drive drive = buildDrive();
Drive.Files.Delete deleteFile = drive.files().delete(file.getId());
deleteFile.execute();
} catch (IOException ex) {
Log.e(TAG, "deleteFile error: " + ex.toString());
}
}

Call the Files.get API to obtain the file metadata.

/**
* Obtain the file metadata.
*
* @param fileId File ID.
*/
private File getFileMetadata(String fileId) {
File file = null;
try {
Drive drive = buildDrive();
Drive.Files.Get request = drive.files().get(fileId);
request.setFields("*");
file = request.execute();
} catch (Exception e) {
Logger.e(TAG, "get metadata error: " + e.toString());
}
return file;
}

Call the Files.get API to download the file metadata and content. A file of any size can be downloaded. To download a file smaller than 20 MB, set directDownloadEnabled to true. Then, simply download the file through a network request.

/**
* Download the file metadata and content.
*
* @param fileId File ID.
* @param destFile Target file.
*/
private void downLoadFile(String fileId, java.io.File destFile) {
if (fileId == null || destFile == null) {
return;
}
try {
Drive drive = buildDrive();
Drive.Files.Get request = drive.files().get(fileId);
File fileContent = request.execute();
long size = fileContent.getSize();
Drive.Files.Get downloadRequest = drive.files().get(fileId);
MediaHttpDownloader downloader = downloadRequest.getMediaHttpDownloader();
boolean isDirectDownload = false;
// Download the file using the simple download method if it is smaller than 20 MB.
if (size < DIRECT_DOWNLOAD_MAX_SIZE) {
isDirectDownload = true;
}
// Set the range. This parameter is mandatory when the simple download method is not uesd.
downloader.setContentRange(0, size - 1);
// Set the download method. By default, a download method rather than simple download is used. If the file is smaller than 20 MB, set this parameter to true.
downloader.setDirectDownloadEnabled(isDirectDownload);
// Set the progress callback listener.
downloadRequest.getMediaHttpDownloader().setProgressListener(new MediaHttpDownloaderProgressListener() {
@Override
public void progressChanged(MediaHttpDownloader downloader) throws IOException {
// Download progress notification.
}
});
downloadRequest.executeContentAndDownloadTo(new FileOutputStream(destFile));
} catch (Exception e) {
Logger.e(TAG, "download file error:" + fileId + e.getMessage());
if (destFile != null) {
// If the download fails, delete the temporary file.
if (destFile.exists()) {
boolean isDeleteSuccess = destFile.delete();
if (!isDeleteSuccess) {
Logger.e(TAG, "downLoadFile delete file fail");
}
}
}
}
}

Call the Files.list API to search for files.

/**
* Search for files.
* @param query Query parameter. For details, please refer to Q statements.
* @param orderBy Sorting field.
* @param pageSize Maximum number of files to return per page.
* @param fields Fields to be contained in the response.
*/
private List<File> getFileList(String query, String orderBy, int pageSize, String fields){
List<File> fileList = null;
try{
Drive drive = buildDrive();
Drive.Files.List request = drive.files().list();
String cursor = null;
fileList = new ArrayList<>();
do {
FileList result = null;
result = request.setQueryParam(query)
.setOrderBy(orderBy)
.setPageSize(pageSize)
.setFields(fields)
.execute();
for (File file : result.getFiles()) {
fileList.add(file);
}
cursor = result.getNextCursor();
request.setCursor(cursor);
}while(!StringUtils.isNullOrEmpty(cursor));
}catch (Exception e) {
Logger.e(TAG, "executeFilesList exception: " + e.toString());
}
return fileList;
}

Call the Files.subscribe API to register the channel for tracking changes made to the designated file and enable change notification for the file.

/**
* register to the channel for tracking changes made to the designated file and enable change notification for the file.
*
* @param fileId File ID
*/
private void filesWatch(String fileId) {
try {
Drive drive = buildDrive();
Channel content = new Channel();
content.setType("web_hook");
content.setUrl("https://xxxx.com"); // Address of the server to which file changes will be sent. You need to build the server.
Drive.Files.Subscribe request = drive.files().subscribe(fileId, content);
Channel channel = request.execute();
SharedPreferences prefs = context.getSharedPreferences("channel_config", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("id", channel.getId());
editor.putString("resourceId", channel.getResourceId());
editor.commit();
} catch (Exception e) {
Log.e(TAG, "Exception" + e.getCause());
}
}