Developer Console

SDK for Android Sample App

Building an Amazon Drive file explorer

sample app login
sample app login

Getting the Source

The source for the sample files is in the Apps-SDK.zip. Unpack the Apps-SDK.zip file and copy Apps-SDK/Android/AmazonCloudDrive/1.0.0/samples/SampleFilesApp to your IDE's workspace directory.

Building and Installing from Android Studio

  1. Launch Android Studio.
  2. Select File -> Import Project….
  3. Navigate to the directory where Apps-SDK was unzipped, select the Apps-SDK/Android/AmazonCloudDrive/1.0.0/samples/SampleFilesApp directory, and click OK.
  4. Select Run -> Run 'app'.

Building and Installing from the Command Line

  1. Get Gradle if you do not already have it.
  2. In the Apps-SDK/Android/AmazonCloudDrive/1.0.0/samples/SampleFilesApp directory, run:

    `gradle build

    adb install -r -d app/build/outputs/apk/app-debug.apk`

API Key

The SampleFilesApp comes with an api_key.txt that works when signed with debug.3p.keystore. When building a real application, you will need to create your own API key. See instructions in the tutorial for creating an api_key.txt.

Code Examples

The SampleFilesApp list nodes, uploads, and downloads files. This section covers how the application accomplishes those tasks with the AmazonCloudDriveClient.

AmazonCloudDriveClient Instance

There is a single client instance that is used for the application. AmazonCloudDriveClient caches the endpoints that it needs to make requests. Using the same instance reduces the total amount of calls to Amazon Drive and makes the requests faster.

/**
 * Gets the global instance of the AmazonCloudDriveClient
 * @param context an application Context
 * @return the client
 */
public static synchronized AmazonCloudDriveClient getAmazonCloudDriveClientInstance(Context context) {
    if (sAmazonCloudDriveClient == null) {
        sAmazonCloudDriveClient = new AmazonCloudDriveClient(
            new AccountConfiguration(
                    new AmazonAuthorizationConnectionFactory(
                            getAmazonAuthorizationManagerInstance(context),
                            Constants.APP_AUTHORIZATION_SCOPES)),
            new ClientConfiguration(Constants.USER_AGENT));
    }

    return sAmazonCloudDriveClient;
}

Uploading Files

Files can be uploaded using the uploadFile and uploadFileAsync methods. The SampleFilesApp uses an IntentService (CloudDriveUploadService) to upload files that have been enqueued. Because the IntentService starts a background thread, it uses the synchronous uploadFile method.

// Upload the file with the root as its parent.
List<String> parents = new ArrayList<String>();
parents.add(getRootNodeId());
UploadFileRequest uploadFileRequest = new UploadFileRequest(
        stagedUploadFile.getName(),
        new FileInputStream(stagedUploadFile),
        stagedUploadFile.length());
uploadFileRequest.setParents(parents);
uploadFileRequest.setSuppress(Suppress.Deduplication);
mAmazonCloudDriveClient.uploadFile(uploadFileRequest, new ProgressListener() {
    @Override
    public void onProgress(long progress, long maxProgress) {
        // Progress is reported on the background thread. Notifications can be updated
        // from the background thread so there is no need to post a message to the
        // main thread.

        // Rebase progress to be in Integer.MAX_VALUE scale so that we can pass it to
        // Android's progress bar.
        int rebasedProgress = (int)(Integer.MAX_VALUE * (progress / (double) maxProgress));
        mNotificationBuilder.setProgress(rebasedProgress, Integer.MAX_VALUE, false);

        // Report progress to notification
        mNotificationManager.notify(R.id.upload_notification, mNotificationBuilder.build());
    }
});

Progress is shown to the user in the form of a notification.

Downloading Files

Files are downloaded and opened using a modal dialog (DownloadDialog). The file is downloaded to an internal directory the opened with an available application by sending an Intent. This code is responsible for downloading the file and reporting progress:

// Create file
File directory = new File(getActivity().getFilesDir(), "/nodes/" + id + "/content/");
directory.mkdirs();
File file = new File(directory, fileName);
OutputStream outputStream = new FileOutputStream(file);

// Setup a ProgressListener that will report progress to the AsyncTask
ProgressListener progressListener = new ProgressListener() {
    @Override
    public void onProgress(final long progress, final long maxProgress) {
        //
        // This callback happens on the background thread. We will
        // post to the main thread by using publishProgress() so
        // the ProgressBar can be updated.
        //
        // The progress from the client is a long, but Android progress
        // bars require an int. This is usually not an issue, but can
        // be a problem for very large files. The progress is rebased
        // to Integer.MAX_VALUE to avoid this issue.
        //
        publishProgress(
                (int)(Integer.MAX_VALUE * (progress / (double) maxProgress)),
                Integer.MAX_VALUE);
    }
};

// Download the File
DownloadFileRequest downloadFileRequest = new DownloadFileRequest(nodeId, outputStream);
mAmazonCloudDriveClient.downloadFile(downloadFileRequest, progressListener);

The content is downloaded to an internal directory and served through a ContentProvider to external applications.

Listing Nodes

The application gets node data with the CloudDriveFolderListingService. There are two situations: one where we know what the node ID is that we want to list, and the case where the node we want to list is the root. In the case where we know what the node is we want to list, we use the listChildren method specifying the node ID whose children we want to list. It is possible that it will return more than one page of results. To get all of the results, we need to keep getting pages until the nextToken is null.

// ListChildren is an example of a paged request. We may not get all
// of the nodes back in one request, so we will need to keep looping
// until we get all of the a null next token as a response.
String nextToken = null;
do {
    // Make a synchronous (blocking) call to Amazon Drive that lists
    // all of the children for the node.
    ListChildrenRequest listChildrenRequest = new ListChildrenRequest(id);
    listChildrenRequest.setStartToken(nextToken);
    ListChildrenResponse response = mAmazonCloudDriveClient.listChildren(listChildrenRequest);
    nextToken = response.getNextToken();
    List<Node> nodes = response.getData();

    // ...
}
while (nextToken != null);

To list the root folder, we need to resolve the root node first. To get the root node, we use the filtering capability of listNodes. The filter "isRoot:true" gives us back the one and only root node for Amazon Drive. See filters for more about filtering listNodes and listChildren.

// To list the root node, we filter to only show the nodes that
// have the property isRoot set to true. To learn more about
// filtering, see https://developer.amazon.com/public/apis/experience/cloud-drive/content/nodes#Filtering
ListNodesRequest listNodesRequest = new ListNodesRequest();
String filters = "isRoot:true";
listNodesRequest.setFilters(filters);

// Make a synchronous (blocking) call to Amazon Drive that lists
// the root node.
ListNodesResponse listNodesResponse = mAmazonCloudDriveClient.listNodes(listNodesRequest);
List<Node> nodes = listNodesResponse.getData();

Providing a Local Interface to Nodes

The SampleFilesApp uses a ContentProvider (CloudDriveProvider) to provide an interface to the nodes. This is used internally for the folder listing and as a way for external applications to read the binary content.

Folder Listing Cache

The node metadata is inserted into the database when the CloudDriveFolderListingService receives an Intent to refresh the folder. This data is read by the NodeListingFragment using the CloudDriveProvider through a CursorLoader.

return new CursorLoader(
      getActivity(),
      CloudDriveContract.NodeChildren.CONTENT_URI,
      new String[]{
              CloudDriveContract.NodeChildren._ID,
              CloudDriveContract.NodeChildren.NODE_ID,
              CloudDriveContract.NodeChildren.NAME,
              CloudDriveContract.NodeChildren.KIND,
              CloudDriveContract.NodeChildren.MODIFIED_DATE},
      CloudDriveContract.NodeChildren.STATUS + " != ?" +
              " AND " + CloudDriveContract.NodeChildren.STATUS + " != ?" +
              " AND " + CloudDriveContract.NodeChildren.KIND + " != ?" +
              " AND " + CloudDriveContract.NodeChildren.PARENT_IS_ROOT + " = ?",
      new String[]{"PURGED", "TRASH", "ASSET", "1"},
      CloudDriveContract.NodeChildren.KIND + " DESC, " + CloudDriveContract.NodeChildren.NAME + " ASC ");

Binary Content Provider

The CloudDriveProvider grants applications access to the content URI by specifying grantUriPermissions in the ContentProvider declaration. It is worth noting that the ContentProvider is not exported. Exporting the ContentProvider would allow other applications to be able to read all of the customer's metadata. Because even the names of the files are secret customer information, we need to protect it.

<provider
    android:authorities="com.example.clouddrivefiles"
    android:name=".provider.CloudDriveProvider"
    android:exported="false"
    android:grantUriPermissions="true" />

Applications expect to be able to read a few metadata fields from content:// URIs. We make these available by inserting these values into our database and fronting them with the CloudDriveProvider.

// Write the node contents row
ContentValues contentValues = new ContentValues();
contentValues.put(CloudDriveContract.NodeContents._ID, id);
contentValues.put(CloudDriveContract.NodeContents.DATA, file.toString());
contentValues.put(CloudDriveContract.NodeContents.DISPLAY_NAME, fileName);
contentValues.put(CloudDriveContract.NodeContents.SIZE, file.length());
activity.getContentResolver().insert(uri, contentValues);

Troubleshooting

The SampleFilesApp project requires the v7 appcompat library. If you do not have this installed with your Android SDK, install it using the SDK updater https://developer.android.com/tools/support-library/features.html

Support

If you have any questions, see the Developer Forum.