@@ -519,11 +519,18 @@ public class JuceDemo extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JuceDemo.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemo.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -538,11 +545,18 @@ public class JuceDemo extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JuceDemo.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemo.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -550,7 +564,7 @@ public class JuceDemo extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemo.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -564,11 +578,18 @@ public class JuceDemo extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JuceDemo.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemo.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -576,7 +597,7 @@ public class JuceDemo extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemo.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -584,7 +605,7 @@ public class JuceDemo extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemo.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -982,13 +1003,75 @@ public class JuceDemo extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1011,19 +1094,12 @@ public class JuceDemo extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1031,6 +1107,89 @@ public class JuceDemo extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1068,9 +1227,16 @@ public class JuceDemo extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -1173,13 +1339,20 @@ public class JuceDemo extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -1201,89 +1374,15 @@ public class JuceDemo extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -1309,7 +1408,14 @@ public class JuceDemo extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -1404,7 +1510,7 @@ public class JuceDemo extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
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") | |||
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 | |||
"../../../JuceLibraryCode" | |||
@@ -519,11 +519,18 @@ public class InAppPurchase extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
InAppPurchase.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
InAppPurchase.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -538,11 +545,18 @@ public class InAppPurchase extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
InAppPurchase.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
InAppPurchase.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -550,7 +564,7 @@ public class InAppPurchase extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
InAppPurchase.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -564,11 +578,18 @@ public class InAppPurchase extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
InAppPurchase.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
InAppPurchase.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -576,7 +597,7 @@ public class InAppPurchase extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
InAppPurchase.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -584,7 +605,7 @@ public class InAppPurchase extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
InAppPurchase.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -982,13 +1003,75 @@ public class InAppPurchase extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1011,19 +1094,12 @@ public class InAppPurchase extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1031,6 +1107,89 @@ public class InAppPurchase extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1068,9 +1227,16 @@ public class InAppPurchase extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -1173,13 +1339,20 @@ public class InAppPurchase extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -1201,89 +1374,15 @@ public class InAppPurchase extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -1309,7 +1408,14 @@ public class InAppPurchase extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -1404,7 +1510,7 @@ public class InAppPurchase extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
return android.os.Build.VERSION.SDK_INT; | |||
} | |||
@@ -223,6 +223,7 @@ | |||
GCC_PREPROCESSOR_DEFINITIONS = ( | |||
"_DEBUG=1", | |||
"DEBUG=1", | |||
"JUCE_IN_APP_PURCHASES=1", | |||
"JUCER_XCODE_IPHONE_5BC26AE3=1", | |||
"JUCE_APP_VERSION=0.0.2", | |||
"JUCE_APP_VERSION_HEX=0x2", | |||
@@ -254,6 +255,7 @@ | |||
GCC_PREPROCESSOR_DEFINITIONS = ( | |||
"_NDEBUG=1", | |||
"NDEBUG=1", | |||
"JUCE_IN_APP_PURCHASES=1", | |||
"JUCER_XCODE_IPHONE_5BC26AE3=1", | |||
"JUCE_APP_VERSION=0.0.2", | |||
"JUCE_APP_VERSION_HEX=0x2", | |||
@@ -1448,11 +1448,18 @@ public class MidiTest extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
MidiTest.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
MidiTest.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1467,11 +1474,18 @@ public class MidiTest extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
MidiTest.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
MidiTest.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -1479,7 +1493,7 @@ public class MidiTest extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
MidiTest.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1493,11 +1507,18 @@ public class MidiTest extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
MidiTest.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
MidiTest.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -1505,7 +1526,7 @@ public class MidiTest extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
MidiTest.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -1513,7 +1534,7 @@ public class MidiTest extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
MidiTest.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1911,13 +1932,75 @@ public class MidiTest extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1940,19 +2023,12 @@ public class MidiTest extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1960,6 +2036,89 @@ public class MidiTest extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1997,9 +2156,16 @@ public class MidiTest extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -2102,13 +2268,20 @@ public class MidiTest extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -2130,89 +2303,15 @@ public class MidiTest extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -2238,7 +2337,14 @@ public class MidiTest extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -2333,7 +2439,7 @@ public class MidiTest extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
return android.os.Build.VERSION.SDK_INT; | |||
} | |||
@@ -519,11 +519,18 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -538,11 +545,18 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -550,7 +564,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -564,11 +578,18 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -576,7 +597,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -584,7 +605,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JUCENetworkGraphicsDemo.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -982,13 +1003,75 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1011,19 +1094,12 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1031,6 +1107,89 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1068,9 +1227,16 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -1173,13 +1339,20 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -1201,89 +1374,15 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -1309,7 +1408,14 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -1404,7 +1510,7 @@ public class JUCENetworkGraphicsDemo extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
return android.os.Build.VERSION.SDK_INT; | |||
} | |||
@@ -519,11 +519,18 @@ public class OSCReceiver extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
OSCReceiver.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCReceiver.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -538,11 +545,18 @@ public class OSCReceiver extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
OSCReceiver.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCReceiver.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -550,7 +564,7 @@ public class OSCReceiver extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCReceiver.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -564,11 +578,18 @@ public class OSCReceiver extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
OSCReceiver.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCReceiver.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -576,7 +597,7 @@ public class OSCReceiver extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCReceiver.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -584,7 +605,7 @@ public class OSCReceiver extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCReceiver.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -982,13 +1003,75 @@ public class OSCReceiver extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1011,19 +1094,12 @@ public class OSCReceiver extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1031,6 +1107,89 @@ public class OSCReceiver extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1068,9 +1227,16 @@ public class OSCReceiver extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -1173,13 +1339,20 @@ public class OSCReceiver extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -1201,89 +1374,15 @@ public class OSCReceiver extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -1309,7 +1408,14 @@ public class OSCReceiver extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -1404,7 +1510,7 @@ public class OSCReceiver extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
return android.os.Build.VERSION.SDK_INT; | |||
} | |||
@@ -519,11 +519,18 @@ public class OSCSender extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
OSCSender.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCSender.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -538,11 +545,18 @@ public class OSCSender extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
OSCSender.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCSender.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -550,7 +564,7 @@ public class OSCSender extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCSender.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -564,11 +578,18 @@ public class OSCSender extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
OSCSender.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCSender.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -576,7 +597,7 @@ public class OSCSender extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCSender.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -584,7 +605,7 @@ public class OSCSender extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
OSCSender.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -982,13 +1003,75 @@ public class OSCSender extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1011,19 +1094,12 @@ public class OSCSender extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1031,6 +1107,89 @@ public class OSCSender extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1068,9 +1227,16 @@ public class OSCSender extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -1173,13 +1339,20 @@ public class OSCSender extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -1201,89 +1374,15 @@ public class OSCSender extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -1309,7 +1408,14 @@ public class OSCSender extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -1404,7 +1510,7 @@ public class OSCSender extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
return android.os.Build.VERSION.SDK_INT; | |||
} | |||
@@ -1448,11 +1448,18 @@ public class JuceDemoPlugin extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JuceDemoPlugin.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemoPlugin.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1467,11 +1474,18 @@ public class JuceDemoPlugin extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JuceDemoPlugin.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemoPlugin.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -1479,7 +1493,7 @@ public class JuceDemoPlugin extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemoPlugin.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1493,11 +1507,18 @@ public class JuceDemoPlugin extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
JuceDemoPlugin.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemoPlugin.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -1505,7 +1526,7 @@ public class JuceDemoPlugin extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemoPlugin.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -1513,7 +1534,7 @@ public class JuceDemoPlugin extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
JuceDemoPlugin.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1911,13 +1932,75 @@ public class JuceDemoPlugin extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1940,19 +2023,12 @@ public class JuceDemoPlugin extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1960,6 +2036,89 @@ public class JuceDemoPlugin extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1997,9 +2156,16 @@ public class JuceDemoPlugin extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -2102,13 +2268,20 @@ public class JuceDemoPlugin extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -2130,89 +2303,15 @@ public class JuceDemoPlugin extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -2238,7 +2337,14 @@ public class JuceDemoPlugin extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -2333,7 +2439,7 @@ public class JuceDemoPlugin extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
return android.os.Build.VERSION.SDK_INT; | |||
} | |||
@@ -1448,11 +1448,18 @@ public class AudioPerformanceTest extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
AudioPerformanceTest.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("OK", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
AudioPerformanceTest.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1467,11 +1474,18 @@ public class AudioPerformanceTest extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
AudioPerformanceTest.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton (okButtonText.isEmpty() ? "OK" : okButtonText, new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
AudioPerformanceTest.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -1479,7 +1493,7 @@ public class AudioPerformanceTest extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
AudioPerformanceTest.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1493,11 +1507,18 @@ public class AudioPerformanceTest extends Activity | |||
builder.setTitle (title) | |||
.setMessage (message) | |||
.setCancelable (true) | |||
.setOnCancelListener (new DialogInterface.OnCancelListener() | |||
{ | |||
public void onCancel (DialogInterface dialog) | |||
{ | |||
AudioPerformanceTest.this.alertDismissed (callback, 0); | |||
} | |||
}) | |||
.setPositiveButton ("Yes", new DialogInterface.OnClickListener() | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
AudioPerformanceTest.this.alertDismissed (callback, 1); | |||
} | |||
}) | |||
@@ -1505,7 +1526,7 @@ public class AudioPerformanceTest extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
AudioPerformanceTest.this.alertDismissed (callback, 2); | |||
} | |||
}) | |||
@@ -1513,7 +1534,7 @@ public class AudioPerformanceTest extends Activity | |||
{ | |||
public void onClick (DialogInterface dialog, int id) | |||
{ | |||
dialog.cancel(); | |||
dialog.dismiss(); | |||
AudioPerformanceTest.this.alertDismissed (callback, 0); | |||
} | |||
}); | |||
@@ -1911,13 +1932,75 @@ public class AudioPerformanceTest extends Activity | |||
//============================================================================== | |||
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 | |||
@@ -1940,19 +2023,12 @@ public class AudioPerformanceTest extends Activity | |||
try | |||
{ | |||
if (connection.getConnectTimeout() > 0) | |||
return streamFuture.get (connection.getConnectTimeout(), TimeUnit.MILLISECONDS); | |||
else | |||
return streamFuture.get(); | |||
return streamFuture.get(); | |||
} | |||
catch (InterruptedException e) | |||
{ | |||
return null; | |||
} | |||
catch (TimeoutException e) | |||
{ | |||
return null; | |||
} | |||
catch (CancellationException e) | |||
{ | |||
return null; | |||
@@ -1960,6 +2036,89 @@ public class AudioPerformanceTest extends Activity | |||
} | |||
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) | |||
{ | |||
@@ -1997,9 +2156,16 @@ public class AudioPerformanceTest extends Activity | |||
{} | |||
for (java.util.Map.Entry<String, java.util.List<String>> entry : connection.getHeaderFields().entrySet()) | |||
{ | |||
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; | |||
} | |||
@@ -2102,13 +2268,20 @@ public class AudioPerformanceTest extends Activity | |||
} | |||
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 setPosition (long newPos) { return false; } | |||
private boolean isPost; | |||
private byte[] postData; | |||
private String headers; | |||
private int timeOutMs; | |||
String httpRequestCmd; | |||
private HttpURLConnection connection; | |||
private int[] statusCode; | |||
private StringBuffer responseHeaders; | |||
private int totalLength; | |||
private int numRedirectsToFollow; | |||
private InputStream inputStream; | |||
private long position; | |||
private final ReentrantLock createStreamLock = new ReentrantLock(); | |||
@@ -2130,89 +2303,15 @@ public class AudioPerformanceTest extends Activity | |||
else if (timeOutMs == 0) | |||
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 (;;) | |||
{ | |||
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) {} | |||
@@ -2238,7 +2337,14 @@ public class AudioPerformanceTest extends Activity | |||
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 getMusicFolder() { return getFileLocation (Environment.DIRECTORY_MUSIC); } | |||
public static final String getMoviesFolder() { return getFileLocation (Environment.DIRECTORY_MOVIES); } | |||
@@ -2333,7 +2439,7 @@ public class AudioPerformanceTest extends Activity | |||
return null; | |||
} | |||
public final int getAndroidSDKVersion() | |||
public static final int getAndroidSDKVersion() | |||
{ | |||
return android.os.Build.VERSION.SDK_INT; | |||
} | |||
@@ -1540,9 +1540,9 @@ static const unsigned char temp_binary_data_8[] = | |||
" #endif\r\n" | |||
"}\r\n" | |||
"\r\n" | |||
"bool FILTERCLASSNAME::isMidiEffect () const\r\n" | |||
"bool FILTERCLASSNAME::isMidiEffect() const\r\n" | |||
"{\r\n" | |||
" #ifdef JucePlugin_IsMidiEffect\r\n" | |||
" #if JucePlugin_IsMidiEffect\r\n" | |||
" return true;\r\n" | |||
" #else\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 0x27c5a93a: numBytes = 1310; return jucer_AudioPluginEditorTemplate_cpp; | |||
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 0xabad7041: numBytes = 2151; return jucer_ComponentTemplate_cpp; | |||
case 0xfc72fe86: numBytes = 2064; return jucer_ComponentTemplate_h; | |||
@@ -33,7 +33,7 @@ namespace BinaryData | |||
const int jucer_AudioPluginEditorTemplate_hSize = 938; | |||
extern const char* jucer_AudioPluginFilterTemplate_cpp; | |||
const int jucer_AudioPluginFilterTemplate_cppSize = 5615; | |||
const int jucer_AudioPluginFilterTemplate_cppSize = 5611; | |||
extern const char* jucer_AudioPluginFilterTemplate_h; | |||
const int jucer_AudioPluginFilterTemplate_hSize = 2245; | |||