aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Dart <keith.dart@gmail.com>2017-09-28 17:54:57 -0700
committerAng Li <angli@google.com>2017-09-28 17:54:57 -0700
commit2797e51535fd0906326ba8785159d6d2f96f1e7d (patch)
treee2a5b29bdd54403b2284b7b406d686956adcb68a
parent7f7798eb4b720054f40e0f507c0b2824cabbb405 (diff)
downloadmobly-bundled-snippets-2797e51535fd0906326ba8785159d6d2f96f1e7d.tar.gz
Add Rpcs needed to download files via HTTP. (#80)
* Add an Rpc to perform an HTTP download using DownloadManager. * Add file operation Rpcs.
-rw-r--r--src/main/AndroidManifest.xml2
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/FileSnippet.java75
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/NetworkingSnippet.java87
-rw-r--r--src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java22
4 files changed, 185 insertions, 1 deletions
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index ef882c8..dc5d0af 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -13,6 +13,7 @@
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
@@ -38,6 +39,7 @@
com.google.android.mobly.snippet.bundled.NotificationSnippet,
com.google.android.mobly.snippet.bundled.TelephonySnippet,
com.google.android.mobly.snippet.bundled.NetworkingSnippet,
+ com.google.android.mobly.snippet.bundled.FileSnippet,
com.google.android.mobly.snippet.bundled.SmsSnippet,
com.google.android.mobly.snippet.bundled.WifiManagerSnippet" />
</application>
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/FileSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/FileSnippet.java
new file mode 100644
index 0000000..571d57f
--- /dev/null
+++ b/src/main/java/com/google/android/mobly/snippet/bundled/FileSnippet.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2017 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.google.android.mobly.snippet.bundled;
+
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.DigestInputStream;
+import java.security.NoSuchAlgorithmException;
+import android.content.Context;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
+import com.google.android.mobly.snippet.Snippet;
+import com.google.android.mobly.snippet.bundled.utils.Utils;
+import com.google.android.mobly.snippet.rpc.Rpc;
+
+/** Snippet class for File and abstract storage URI operation RPCs. */
+public class FileSnippet implements Snippet {
+
+ private final Context mContext;
+
+ public FileSnippet() {
+ mContext = InstrumentationRegistry.getContext();
+ }
+
+ private static class FileSnippetException extends Exception {
+
+ private static final long serialVersionUID = 8081L;
+
+ public FileSnippetException(String msg) {
+ super(msg);
+ }
+ }
+
+ @Rpc(description = "Compute MD5 hash on a content URI. Return the MD5 has has a hex string.")
+ public String fileMd5Hash(String uri) throws IOException, NoSuchAlgorithmException {
+ Uri uri_ = Uri.parse(uri);
+ ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(uri_, "r");
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ int length = (int) pfd.getStatSize();
+ byte[] buf = new byte[length];
+ ParcelFileDescriptor.AutoCloseInputStream stream = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ DigestInputStream dis = new DigestInputStream(stream, md);
+ try {
+ dis.read(buf, 0, length);
+ return Utils.bytesToHexString(md.digest());
+ } finally {
+ dis.close();
+ stream.close();
+ }
+ }
+
+ @Rpc(description = "Remove a file pointed to by the content URI.")
+ public void fileDeleteContent(String uri) {
+ Uri uri_ = Uri.parse(uri);
+ mContext.getContentResolver().delete(uri_, null, null);
+ }
+
+ @Override
+ public void shutdown() {}
+}
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/NetworkingSnippet.java b/src/main/java/com/google/android/mobly/snippet/bundled/NetworkingSnippet.java
index d72205a..f175fdd 100644
--- a/src/main/java/com/google/android/mobly/snippet/bundled/NetworkingSnippet.java
+++ b/src/main/java/com/google/android/mobly/snippet/bundled/NetworkingSnippet.java
@@ -16,17 +16,47 @@
package com.google.android.mobly.snippet.bundled;
+import java.util.List;
import java.net.InetAddress;
import java.net.Socket;
import java.io.IOException;
import java.net.UnknownHostException;
+import android.content.Intent;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.BroadcastReceiver;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.app.DownloadManager;
+import android.support.test.InstrumentationRegistry;
import com.google.android.mobly.snippet.Snippet;
+import com.google.android.mobly.snippet.bundled.utils.Utils;
import com.google.android.mobly.snippet.rpc.Rpc;
import com.google.android.mobly.snippet.util.Log;
/** Snippet class for networking RPCs. */
public class NetworkingSnippet implements Snippet {
+ private final Context mContext;
+ private final DownloadManager mDownloadManager;
+ private volatile boolean mIsDownloadComplete = false;
+ private volatile long mReqid = 0;
+
+ public NetworkingSnippet() {
+ mContext = InstrumentationRegistry.getContext();
+ mDownloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
+ }
+
+ private static class NetworkingSnippetException extends Exception {
+
+ private static final long serialVersionUID = 8080L;
+
+ public NetworkingSnippetException(String msg) {
+ super(msg);
+ }
+ }
+
@Rpc(description = "Check if a host and port are connectable using a TCP connection attempt.")
public boolean networkIsTcpConnectable(String host, int port) {
InetAddress addr;
@@ -47,6 +77,61 @@ public class NetworkingSnippet implements Snippet {
return true;
}
+ @Rpc(description = "Download a file using HTTP. Return content Uri (file remains on device). "
+ + "The Uri should be treated as an opaque handle for further operations.")
+ public String networkHttpDownload(String url) throws IllegalArgumentException, NetworkingSnippetException {
+
+ Uri uri = Uri.parse(url);
+ List<String> pathsegments = uri.getPathSegments();
+ if (pathsegments.size() < 1) {
+ throw new IllegalArgumentException(String.format("The Uri %s does not have a path.", uri.toString()));
+ }
+ DownloadManager.Request request = new DownloadManager.Request(uri);
+ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,
+ pathsegments.get(pathsegments.size() - 1));
+ mIsDownloadComplete = false;
+ mReqid = 0;
+ IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
+ BroadcastReceiver receiver = new DownloadReceiver();
+ mContext.registerReceiver(receiver, filter);
+ try {
+ mReqid = mDownloadManager.enqueue(request);
+ Log.d(String.format("networkHttpDownload download of %s with id %d", url, mReqid));
+ if (!Utils.waitUntil(() -> mIsDownloadComplete, 30)) {
+ Log.d(String.format("networkHttpDownload timed out waiting for completion"));
+ throw new NetworkingSnippetException("networkHttpDownload timed out.");
+ }
+ } finally {
+ mContext.unregisterReceiver(receiver);
+ }
+ Uri resp = mDownloadManager.getUriForDownloadedFile(mReqid);
+ if (resp != null) {
+ Log.d(String.format("networkHttpDownload completed to %s", resp.toString()));
+ mReqid = 0;
+ return resp.toString();
+ } else {
+ Log.d(String.format("networkHttpDownload Failed to download %s", uri.toString()));
+ throw new NetworkingSnippetException("networkHttpDownload didn't get downloaded file.");
+ }
+ }
+
+ private class DownloadReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ long gotid = (long) intent.getExtras().get("extra_download_id");
+ if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)
+ && gotid == mReqid) {
+ mIsDownloadComplete = true;
+ }
+ }
+ }
+
@Override
- public void shutdown() {}
+ public void shutdown() {
+ if (mReqid != 0) {
+ mDownloadManager.remove(mReqid);
+ }
+ }
}
diff --git a/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java b/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java
index c68ae5a..e4c0dbd 100644
--- a/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java
+++ b/src/main/java/com/google/android/mobly/snippet/bundled/utils/Utils.java
@@ -30,6 +30,8 @@ import java.util.concurrent.TimeoutException;
public final class Utils {
+ private final static char[] hexArray = "0123456789abcdef".toCharArray();
+
private Utils() {}
/**
@@ -190,4 +192,24 @@ public final class Utils {
throw e.getCause();
}
}
+
+ /**
+ * Convert a byte array (binary data) to a hexadecimal string (ASCII)
+ * representation.
+
+ * [\x01\x02] -&gt; "0102"
+ *
+ * @param bytes The array of byte to convert.
+ * @return a String with the ASCII hex representation.
+ */
+ public static String bytesToHexString(byte[] bytes) {
+ char[] hexChars = new char[bytes.length * 2];
+ for ( int j = 0; j < bytes.length; j++ ) {
+ int v = bytes[j] & 0xFF;
+ hexChars[j * 2] = hexArray[v >>> 4];
+ hexChars[j * 2 + 1] = hexArray[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+
}