| @@ -519,11 +519,18 @@ public class JuceDemo extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JuceDemo.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemo.this.alertDismissed (callback, 0); | JuceDemo.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -538,11 +545,18 @@ public class JuceDemo extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JuceDemo.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemo.this.alertDismissed (callback, 1); | JuceDemo.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -550,7 +564,7 @@ public class JuceDemo extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemo.this.alertDismissed (callback, 0); | JuceDemo.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -564,11 +578,18 @@ public class JuceDemo extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JuceDemo.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemo.this.alertDismissed (callback, 1); | JuceDemo.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -576,7 +597,7 @@ public class JuceDemo extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemo.this.alertDismissed (callback, 2); | JuceDemo.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -584,7 +605,7 @@ public class JuceDemo extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemo.this.alertDismissed (callback, 0); | JuceDemo.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -982,13 +1003,75 @@ public class JuceDemo extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1011,19 +1094,12 @@ public class JuceDemo extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1031,6 +1107,89 @@ public class JuceDemo extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1068,9 +1227,16 @@ public class JuceDemo extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -1173,13 +1339,20 @@ public class JuceDemo extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -1201,89 +1374,15 @@ public class JuceDemo extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -1309,7 +1408,14 @@ public class JuceDemo extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -1404,7 +1510,7 @@ public class JuceDemo extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -8,7 +8,7 @@ SET(BINARY_NAME "juce_jni") | |||||
| add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c") | add_library("cpufeatures" STATIC "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c") | ||||
| set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression") | set_source_files_properties("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" PROPERTIES COMPILE_FLAGS "-Wno-sign-conversion -Wno-gnu-statement-expression") | ||||
| add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=10" "-DJUCE_ANDROID_ACTIVITY_CLASSNAME=com_roli_juceinapppurchasesample_InAppPurchase" "-DJUCE_ANDROID_ACTIVITY_CLASSPATH=\"com/roli/juceinapppurchasesample/InAppPurchase\"" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=0.0.2" "-DJUCE_APP_VERSION_HEX=0x2") | |||||
| add_definitions("-DJUCE_ANDROID=1" "-DJUCE_ANDROID_API_VERSION=10" "-DJUCE_ANDROID_ACTIVITY_CLASSNAME=com_roli_juceinapppurchasesample_InAppPurchase" "-DJUCE_ANDROID_ACTIVITY_CLASSPATH=\"com/roli/juceinapppurchasesample/InAppPurchase\"" "-DJUCE_IN_APP_PURCHASES=1" "-DJUCER_ANDROIDSTUDIO_7F0E4A25=1" "-DJUCE_APP_VERSION=0.0.2" "-DJUCE_APP_VERSION_HEX=0x2") | |||||
| include_directories( AFTER | include_directories( AFTER | ||||
| "../../../JuceLibraryCode" | "../../../JuceLibraryCode" | ||||
| @@ -519,11 +519,18 @@ public class InAppPurchase extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| InAppPurchase.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| InAppPurchase.this.alertDismissed (callback, 0); | InAppPurchase.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -538,11 +545,18 @@ public class InAppPurchase extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| InAppPurchase.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| InAppPurchase.this.alertDismissed (callback, 1); | InAppPurchase.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -550,7 +564,7 @@ public class InAppPurchase extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| InAppPurchase.this.alertDismissed (callback, 0); | InAppPurchase.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -564,11 +578,18 @@ public class InAppPurchase extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| InAppPurchase.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| InAppPurchase.this.alertDismissed (callback, 1); | InAppPurchase.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -576,7 +597,7 @@ public class InAppPurchase extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| InAppPurchase.this.alertDismissed (callback, 2); | InAppPurchase.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -584,7 +605,7 @@ public class InAppPurchase extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| InAppPurchase.this.alertDismissed (callback, 0); | InAppPurchase.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -982,13 +1003,75 @@ public class InAppPurchase extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1011,19 +1094,12 @@ public class InAppPurchase extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1031,6 +1107,89 @@ public class InAppPurchase extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1068,9 +1227,16 @@ public class InAppPurchase extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -1173,13 +1339,20 @@ public class InAppPurchase extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -1201,89 +1374,15 @@ public class InAppPurchase extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -1309,7 +1408,14 @@ public class InAppPurchase extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -1404,7 +1510,7 @@ public class InAppPurchase extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -223,6 +223,7 @@ | |||||
| GCC_PREPROCESSOR_DEFINITIONS = ( | GCC_PREPROCESSOR_DEFINITIONS = ( | ||||
| "_DEBUG=1", | "_DEBUG=1", | ||||
| "DEBUG=1", | "DEBUG=1", | ||||
| "JUCE_IN_APP_PURCHASES=1", | |||||
| "JUCER_XCODE_IPHONE_5BC26AE3=1", | "JUCER_XCODE_IPHONE_5BC26AE3=1", | ||||
| "JUCE_APP_VERSION=0.0.2", | "JUCE_APP_VERSION=0.0.2", | ||||
| "JUCE_APP_VERSION_HEX=0x2", | "JUCE_APP_VERSION_HEX=0x2", | ||||
| @@ -254,6 +255,7 @@ | |||||
| GCC_PREPROCESSOR_DEFINITIONS = ( | GCC_PREPROCESSOR_DEFINITIONS = ( | ||||
| "_NDEBUG=1", | "_NDEBUG=1", | ||||
| "NDEBUG=1", | "NDEBUG=1", | ||||
| "JUCE_IN_APP_PURCHASES=1", | |||||
| "JUCER_XCODE_IPHONE_5BC26AE3=1", | "JUCER_XCODE_IPHONE_5BC26AE3=1", | ||||
| "JUCE_APP_VERSION=0.0.2", | "JUCE_APP_VERSION=0.0.2", | ||||
| "JUCE_APP_VERSION_HEX=0x2", | "JUCE_APP_VERSION_HEX=0x2", | ||||
| @@ -1448,11 +1448,18 @@ public class MidiTest extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| MidiTest.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| MidiTest.this.alertDismissed (callback, 0); | MidiTest.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1467,11 +1474,18 @@ public class MidiTest extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| MidiTest.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| MidiTest.this.alertDismissed (callback, 1); | MidiTest.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1479,7 +1493,7 @@ public class MidiTest extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| MidiTest.this.alertDismissed (callback, 0); | MidiTest.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1493,11 +1507,18 @@ public class MidiTest extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| MidiTest.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| MidiTest.this.alertDismissed (callback, 1); | MidiTest.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1505,7 +1526,7 @@ public class MidiTest extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| MidiTest.this.alertDismissed (callback, 2); | MidiTest.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1513,7 +1534,7 @@ public class MidiTest extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| MidiTest.this.alertDismissed (callback, 0); | MidiTest.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1911,13 +1932,75 @@ public class MidiTest extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1940,19 +2023,12 @@ public class MidiTest extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1960,6 +2036,89 @@ public class MidiTest extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1997,9 +2156,16 @@ public class MidiTest extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -2102,13 +2268,20 @@ public class MidiTest extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -2130,89 +2303,15 @@ public class MidiTest extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -2238,7 +2337,14 @@ public class MidiTest extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -2333,7 +2439,7 @@ public class MidiTest extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -519,11 +519,18 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -538,11 +545,18 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); | JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -550,7 +564,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -564,11 +578,18 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); | JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -576,7 +597,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 2); | JUCENetworkGraphicsDemo.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -584,7 +605,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -982,13 +1003,75 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1011,19 +1094,12 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1031,6 +1107,89 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1068,9 +1227,16 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -1173,13 +1339,20 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -1201,89 +1374,15 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -1309,7 +1408,14 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -1404,7 +1510,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -519,11 +519,18 @@ public class OSCReceiver extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| OSCReceiver.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCReceiver.this.alertDismissed (callback, 0); | OSCReceiver.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -538,11 +545,18 @@ public class OSCReceiver extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| OSCReceiver.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCReceiver.this.alertDismissed (callback, 1); | OSCReceiver.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -550,7 +564,7 @@ public class OSCReceiver extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCReceiver.this.alertDismissed (callback, 0); | OSCReceiver.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -564,11 +578,18 @@ public class OSCReceiver extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| OSCReceiver.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCReceiver.this.alertDismissed (callback, 1); | OSCReceiver.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -576,7 +597,7 @@ public class OSCReceiver extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCReceiver.this.alertDismissed (callback, 2); | OSCReceiver.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -584,7 +605,7 @@ public class OSCReceiver extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCReceiver.this.alertDismissed (callback, 0); | OSCReceiver.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -982,13 +1003,75 @@ public class OSCReceiver extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1011,19 +1094,12 @@ public class OSCReceiver extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1031,6 +1107,89 @@ public class OSCReceiver extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1068,9 +1227,16 @@ public class OSCReceiver extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -1173,13 +1339,20 @@ public class OSCReceiver extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -1201,89 +1374,15 @@ public class OSCReceiver extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -1309,7 +1408,14 @@ public class OSCReceiver extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -1404,7 +1510,7 @@ public class OSCReceiver extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -519,11 +519,18 @@ public class OSCSender extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| OSCSender.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCSender.this.alertDismissed (callback, 0); | OSCSender.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -538,11 +545,18 @@ public class OSCSender extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| OSCSender.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCSender.this.alertDismissed (callback, 1); | OSCSender.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -550,7 +564,7 @@ public class OSCSender extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCSender.this.alertDismissed (callback, 0); | OSCSender.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -564,11 +578,18 @@ public class OSCSender extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| OSCSender.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCSender.this.alertDismissed (callback, 1); | OSCSender.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -576,7 +597,7 @@ public class OSCSender extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCSender.this.alertDismissed (callback, 2); | OSCSender.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -584,7 +605,7 @@ public class OSCSender extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| OSCSender.this.alertDismissed (callback, 0); | OSCSender.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -982,13 +1003,75 @@ public class OSCSender extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1011,19 +1094,12 @@ public class OSCSender extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1031,6 +1107,89 @@ public class OSCSender extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1068,9 +1227,16 @@ public class OSCSender extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -1173,13 +1339,20 @@ public class OSCSender extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -1201,89 +1374,15 @@ public class OSCSender extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -1309,7 +1408,14 @@ public class OSCSender extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -1404,7 +1510,7 @@ public class OSCSender extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -1448,11 +1448,18 @@ public class JuceDemoPlugin extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 0); | JuceDemoPlugin.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1467,11 +1474,18 @@ public class JuceDemoPlugin extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 1); | JuceDemoPlugin.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1479,7 +1493,7 @@ public class JuceDemoPlugin extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 0); | JuceDemoPlugin.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1493,11 +1507,18 @@ public class JuceDemoPlugin extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 1); | JuceDemoPlugin.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1505,7 +1526,7 @@ public class JuceDemoPlugin extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 2); | JuceDemoPlugin.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1513,7 +1534,7 @@ public class JuceDemoPlugin extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| JuceDemoPlugin.this.alertDismissed (callback, 0); | JuceDemoPlugin.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1911,13 +1932,75 @@ public class JuceDemoPlugin extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1940,19 +2023,12 @@ public class JuceDemoPlugin extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1960,6 +2036,89 @@ public class JuceDemoPlugin extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1997,9 +2156,16 @@ public class JuceDemoPlugin extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -2102,13 +2268,20 @@ public class JuceDemoPlugin extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -2130,89 +2303,15 @@ public class JuceDemoPlugin extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -2238,7 +2337,14 @@ public class JuceDemoPlugin extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -2333,7 +2439,7 @@ public class JuceDemoPlugin extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -1448,11 +1448,18 @@ public class AudioPerformanceTest extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("OK", new DialogInterface.OnClickListener() | .setPositiveButton ("OK", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 0); | AudioPerformanceTest.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1467,11 +1474,18 @@ public class AudioPerformanceTest extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | .setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 1); | AudioPerformanceTest.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1479,7 +1493,7 @@ public class AudioPerformanceTest extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 0); | AudioPerformanceTest.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1493,11 +1507,18 @@ public class AudioPerformanceTest extends Activity | |||||
| builder.setTitle (title) | builder.setTitle (title) | ||||
| .setMessage (message) | .setMessage (message) | ||||
| .setCancelable (true) | .setCancelable (true) | ||||
| .setOnCancelListener (new DialogInterface.OnCancelListener() | |||||
| { | |||||
| public void onCancel (DialogInterface dialog) | |||||
| { | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 0); | |||||
| } | |||||
| }) | |||||
| .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | .setPositiveButton ("Yes", new DialogInterface.OnClickListener() | ||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 1); | AudioPerformanceTest.this.alertDismissed (callback, 1); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1505,7 +1526,7 @@ public class AudioPerformanceTest extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 2); | AudioPerformanceTest.this.alertDismissed (callback, 2); | ||||
| } | } | ||||
| }) | }) | ||||
| @@ -1513,7 +1534,7 @@ public class AudioPerformanceTest extends Activity | |||||
| { | { | ||||
| public void onClick (DialogInterface dialog, int id) | public void onClick (DialogInterface dialog, int id) | ||||
| { | { | ||||
| dialog.cancel(); | |||||
| dialog.dismiss(); | |||||
| AudioPerformanceTest.this.alertDismissed (callback, 0); | AudioPerformanceTest.this.alertDismissed (callback, 0); | ||||
| } | } | ||||
| }); | }); | ||||
| @@ -1911,13 +1932,75 @@ public class AudioPerformanceTest extends Activity | |||||
| //============================================================================== | //============================================================================== | ||||
| public static class HTTPStream | public static class HTTPStream | ||||
| { | { | ||||
| public HTTPStream (HttpURLConnection connection_, | |||||
| int[] statusCode_, | |||||
| StringBuffer responseHeaders_) | |||||
| public HTTPStream (String address, boolean isPostToUse, byte[] postDataToUse, | |||||
| String headersToUse, int timeOutMsToUse, | |||||
| int[] statusCodeToUse, StringBuffer responseHeadersToUse, | |||||
| int numRedirectsToFollowToUse, String httpRequestCmdToUse) throws IOException | |||||
| { | { | ||||
| connection = connection_; | |||||
| statusCode = statusCode_; | |||||
| responseHeaders = responseHeaders_; | |||||
| isPost = isPostToUse; | |||||
| postData = postDataToUse; | |||||
| headers = headersToUse; | |||||
| timeOutMs = timeOutMsToUse; | |||||
| statusCode = statusCodeToUse; | |||||
| responseHeaders = responseHeadersToUse; | |||||
| totalLength = -1; | |||||
| numRedirectsToFollow = numRedirectsToFollowToUse; | |||||
| httpRequestCmd = httpRequestCmdToUse; | |||||
| connection = createConnection (address, isPost, postData, headers, timeOutMs, httpRequestCmd); | |||||
| } | |||||
| private final HttpURLConnection createConnection (String address, boolean isPost, byte[] postData, | |||||
| String headers, int timeOutMs, String httpRequestCmdToUse) throws IOException | |||||
| { | |||||
| HttpURLConnection newConnection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| try | |||||
| { | |||||
| newConnection.setInstanceFollowRedirects (false); | |||||
| newConnection.setConnectTimeout (timeOutMs); | |||||
| newConnection.setReadTimeout (timeOutMs); | |||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| newConnection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| newConnection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| newConnection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = newConnection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| return newConnection; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| newConnection.disconnect(); | |||||
| throw new IOException ("Connection error"); | |||||
| } | |||||
| } | } | ||||
| private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | private final InputStream getCancellableStream (final boolean isInput) throws ExecutionException | ||||
| @@ -1940,19 +2023,12 @@ public class AudioPerformanceTest extends Activity | |||||
| try | try | ||||
| { | { | ||||
| if (connection.getConnectTimeout() > 0) | |||||
| return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||||
| else | |||||
| return streamFuture.get(); | |||||
| return streamFuture.get(); | |||||
| } | } | ||||
| catch (InterruptedException e) | catch (InterruptedException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| } | } | ||||
| catch (TimeoutException e) | |||||
| { | |||||
| return null; | |||||
| } | |||||
| catch (CancellationException e) | catch (CancellationException e) | ||||
| { | { | ||||
| return null; | return null; | ||||
| @@ -1960,6 +2036,89 @@ public class AudioPerformanceTest extends Activity | |||||
| } | } | ||||
| public final boolean connect() | public final boolean connect() | ||||
| { | |||||
| boolean result = false; | |||||
| int numFollowedRedirects = 0; | |||||
| while (true) | |||||
| { | |||||
| result = doConnect(); | |||||
| if (! result) | |||||
| return false; | |||||
| if (++numFollowedRedirects > numRedirectsToFollow) | |||||
| break; | |||||
| int status = statusCode[0]; | |||||
| if (status == 301 || status == 302 || status == 303 || status == 307) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String currentLocation = connection.getURL().toString(); | |||||
| String newLocation = responseHeaders.substring (pos1, pos2); | |||||
| try | |||||
| { | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (currentLocation); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != currentLocation) | |||||
| { | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| synchronized (createStreamLock) | |||||
| { | |||||
| if (hasBeenCancelled.get()) | |||||
| return false; | |||||
| connection.disconnect(); | |||||
| try | |||||
| { | |||||
| connection = createConnection (transformedNewLocation, isPost, | |||||
| postData, headers, timeOutMs, | |||||
| httpRequestCmd); | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| break; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| private final boolean doConnect() | |||||
| { | { | ||||
| synchronized (createStreamLock) | synchronized (createStreamLock) | ||||
| { | { | ||||
| @@ -1997,9 +2156,16 @@ public class AudioPerformanceTest extends Activity | |||||
| {} | {} | ||||
| for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | ||||
| { | |||||
| if (entry.getKey() != null && entry.getValue() != null) | if (entry.getKey() != null && entry.getValue() != null) | ||||
| responseHeaders.append (entry.getKey() + ": " | |||||
| + android.text.TextUtils.join (",", entry.getValue()) + "\n"); | |||||
| { | |||||
| responseHeaders.append(entry.getKey() + ": " | |||||
| + android.text.TextUtils.join(",", entry.getValue()) + "\n"); | |||||
| if (entry.getKey().compareTo ("Content-Length") == 0) | |||||
| totalLength = Integer.decode (entry.getValue().get (0)); | |||||
| } | |||||
| } | |||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -2102,13 +2268,20 @@ public class AudioPerformanceTest extends Activity | |||||
| } | } | ||||
| public final long getPosition() { return position; } | public final long getPosition() { return position; } | ||||
| public final long getTotalLength() { return -1; } | |||||
| public final long getTotalLength() { return totalLength; } | |||||
| public final boolean isExhausted() { return false; } | public final boolean isExhausted() { return false; } | ||||
| public final boolean setPosition (long newPos) { return false; } | public final boolean setPosition (long newPos) { return false; } | ||||
| private boolean isPost; | |||||
| private byte[] postData; | |||||
| private String headers; | |||||
| private int timeOutMs; | |||||
| String httpRequestCmd; | |||||
| private HttpURLConnection connection; | private HttpURLConnection connection; | ||||
| private int[] statusCode; | private int[] statusCode; | ||||
| private StringBuffer responseHeaders; | private StringBuffer responseHeaders; | ||||
| private int totalLength; | |||||
| private int numRedirectsToFollow; | |||||
| private InputStream inputStream; | private InputStream inputStream; | ||||
| private long position; | private long position; | ||||
| private final ReentrantLock createStreamLock = new ReentrantLock(); | private final ReentrantLock createStreamLock = new ReentrantLock(); | ||||
| @@ -2130,89 +2303,15 @@ public class AudioPerformanceTest extends Activity | |||||
| else if (timeOutMs == 0) | else if (timeOutMs == 0) | ||||
| timeOutMs = 30000; | timeOutMs = 30000; | ||||
| // headers - if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. | |||||
| // So convert headers string to an array, with an element for each line | |||||
| String headerLines[] = headers.split("\\n"); | |||||
| for (;;) | for (;;) | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| HttpURLConnection connection = (HttpURLConnection) (new URL(address).openConnection()); | |||||
| HTTPStream httpStream = new HTTPStream (address, isPost, postData, headers, | |||||
| timeOutMs, statusCode, responseHeaders, | |||||
| numRedirectsToFollow, httpRequestCmd); | |||||
| if (connection != null) | |||||
| { | |||||
| try | |||||
| { | |||||
| connection.setInstanceFollowRedirects (false); | |||||
| connection.setConnectTimeout (timeOutMs); | |||||
| connection.setReadTimeout (timeOutMs); | |||||
| // Set request headers | |||||
| for (int i = 0; i < headerLines.length; ++i) | |||||
| { | |||||
| int pos = headerLines[i].indexOf (":"); | |||||
| if (pos > 0 && pos < headerLines[i].length()) | |||||
| { | |||||
| String field = headerLines[i].substring (0, pos); | |||||
| String value = headerLines[i].substring (pos + 1); | |||||
| if (value.length() > 0) | |||||
| connection.setRequestProperty (field, value); | |||||
| } | |||||
| } | |||||
| connection.setRequestMethod (httpRequestCmd); | |||||
| if (isPost) | |||||
| { | |||||
| connection.setDoOutput (true); | |||||
| if (postData != null) | |||||
| { | |||||
| OutputStream out = connection.getOutputStream(); | |||||
| out.write(postData); | |||||
| out.flush(); | |||||
| } | |||||
| } | |||||
| HTTPStream httpStream = new HTTPStream (connection, statusCode, responseHeaders); | |||||
| // Process redirect & continue as necessary | |||||
| int status = statusCode[0]; | |||||
| if (--numRedirectsToFollow >= 0 | |||||
| && (status == 301 || status == 302 || status == 303 || status == 307)) | |||||
| { | |||||
| // Assumes only one occurrence of "Location" | |||||
| int pos1 = responseHeaders.indexOf ("Location:") + 10; | |||||
| int pos2 = responseHeaders.indexOf ("\n", pos1); | |||||
| if (pos2 > pos1) | |||||
| { | |||||
| String newLocation = responseHeaders.substring(pos1, pos2); | |||||
| // Handle newLocation whether it's absolute or relative | |||||
| URL baseUrl = new URL (address); | |||||
| URL newUrl = new URL (baseUrl, newLocation); | |||||
| String transformedNewLocation = newUrl.toString(); | |||||
| if (transformedNewLocation != address) | |||||
| { | |||||
| address = transformedNewLocation; | |||||
| // Clear responseHeaders before next iteration | |||||
| responseHeaders.delete (0, responseHeaders.length()); | |||||
| continue; | |||||
| } | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | |||||
| catch (Throwable e) | |||||
| { | |||||
| connection.disconnect(); | |||||
| } | |||||
| } | |||||
| return httpStream; | |||||
| } | } | ||||
| catch (Throwable e) {} | catch (Throwable e) {} | ||||
| @@ -2238,7 +2337,14 @@ public class AudioPerformanceTest extends Activity | |||||
| return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | return Environment.getExternalStoragePublicDirectory (type).getAbsolutePath(); | ||||
| } | } | ||||
| public static final String getDocumentsFolder() { return Environment.getDataDirectory().getAbsolutePath(); } | |||||
| public static final String getDocumentsFolder() | |||||
| { | |||||
| if (getAndroidSDKVersion() >= 19) | |||||
| return getFileLocation ("Documents"); | |||||
| return Environment.getDataDirectory().getAbsolutePath(); | |||||
| } | |||||
| public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | public static final String getPicturesFolder() { return getFileLocation (Environment.DIRECTORY_PICTURES); } | ||||
| public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | public static final String getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | ||||
| public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | ||||
| @@ -2333,7 +2439,7 @@ public class AudioPerformanceTest extends Activity | |||||
| return null; | return null; | ||||
| } | } | ||||
| public final int getAndroidSDKVersion() | |||||
| public static final int getAndroidSDKVersion() | |||||
| { | { | ||||
| return android.os.Build.VERSION.SDK_INT; | return android.os.Build.VERSION.SDK_INT; | ||||
| } | } | ||||
| @@ -1540,9 +1540,9 @@ static const unsigned char temp_binary_data_8[] = | |||||
| " #endif\r\n" | " #endif\r\n" | ||||
| "}\r\n" | "}\r\n" | ||||
| "\r\n" | "\r\n" | ||||
| "bool FILTERCLASSNAME::isMidiEffect () const\r\n" | |||||
| "bool FILTERCLASSNAME::isMidiEffect() const\r\n" | |||||
| "{\r\n" | "{\r\n" | ||||
| " #ifdef JucePlugin_IsMidiEffect\r\n" | |||||
| " #if JucePlugin_IsMidiEffect\r\n" | |||||
| " return true;\r\n" | " return true;\r\n" | ||||
| " #else\r\n" | " #else\r\n" | ||||
| " return false;\r\n" | " return false;\r\n" | ||||
| @@ -7028,7 +7028,7 @@ const char* getNamedResource (const char* resourceNameUTF8, int& numBytes) throw | |||||
| case 0xafccbd3f: numBytes = 3141; return jucer_AudioComponentTemplate_cpp; | case 0xafccbd3f: numBytes = 3141; return jucer_AudioComponentTemplate_cpp; | ||||
| case 0x27c5a93a: numBytes = 1310; return jucer_AudioPluginEditorTemplate_cpp; | case 0x27c5a93a: numBytes = 1310; return jucer_AudioPluginEditorTemplate_cpp; | ||||
| case 0x4d0721bf: numBytes = 938; return jucer_AudioPluginEditorTemplate_h; | case 0x4d0721bf: numBytes = 938; return jucer_AudioPluginEditorTemplate_h; | ||||
| case 0x51b49ac5: numBytes = 5615; return jucer_AudioPluginFilterTemplate_cpp; | |||||
| case 0x51b49ac5: numBytes = 5611; return jucer_AudioPluginFilterTemplate_cpp; | |||||
| case 0x488afa0a: numBytes = 2245; return jucer_AudioPluginFilterTemplate_h; | case 0x488afa0a: numBytes = 2245; return jucer_AudioPluginFilterTemplate_h; | ||||
| case 0xabad7041: numBytes = 2151; return jucer_ComponentTemplate_cpp; | case 0xabad7041: numBytes = 2151; return jucer_ComponentTemplate_cpp; | ||||
| case 0xfc72fe86: numBytes = 2064; return jucer_ComponentTemplate_h; | case 0xfc72fe86: numBytes = 2064; return jucer_ComponentTemplate_h; | ||||
| @@ -33,7 +33,7 @@ namespace BinaryData | |||||
| const int jucer_AudioPluginEditorTemplate_hSize = 938; | const int jucer_AudioPluginEditorTemplate_hSize = 938; | ||||
| extern const char* jucer_AudioPluginFilterTemplate_cpp; | extern const char* jucer_AudioPluginFilterTemplate_cpp; | ||||
| const int jucer_AudioPluginFilterTemplate_cppSize = 5615; | |||||
| const int jucer_AudioPluginFilterTemplate_cppSize = 5611; | |||||
| extern const char* jucer_AudioPluginFilterTemplate_h; | extern const char* jucer_AudioPluginFilterTemplate_h; | ||||
| const int jucer_AudioPluginFilterTemplate_hSize = 2245; | const int jucer_AudioPluginFilterTemplate_hSize = 2245; | ||||