Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Include new query parameters for device type.

Fix bug in sample where the picture was downloaded on the ui thread.
Add new query parameter logic for upload requests.
Update error messages from server.
  • Loading branch information...
commit 0984e134d214d8b1fde5966624c106f9ab7e79b9 1 parent b0bcd8d
@skrueger skrueger authored
View
25 sample/src/com/microsoft/live/sample/identity/ViewProfileActivity.java
@@ -4,7 +4,7 @@
import android.app.Activity;
import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
@@ -29,6 +29,21 @@
public class ViewProfileActivity extends Activity {
+ private class DownloadProfilePictureAsyncTask extends AsyncTask<LiveDownloadOperation, Void, BitmapDrawable> {
+ @Override
+ protected BitmapDrawable doInBackground(LiveDownloadOperation... params) {
+ return new BitmapDrawable(getResources(), params[0].getStream());
+ }
+
+ @Override
+ protected void onPostExecute(BitmapDrawable profilePicture) {
+ mNameTextView.setCompoundDrawablesWithIntrinsicBounds(profilePicture,
+ null,
+ null,
+ null);
+ }
+ }
+
private TextView mNameTextView;
@Override
@@ -121,11 +136,9 @@ public void onDownloadFailed(LiveOperationException exception,
@Override
public void onDownloadCompleted(LiveDownloadOperation operation) {
- Drawable profilePicture = new BitmapDrawable(operation.getStream());
- mNameTextView.setCompoundDrawablesWithIntrinsicBounds(profilePicture,
- null,
- null,
- null);
+ DownloadProfilePictureAsyncTask task =
+ new DownloadProfilePictureAsyncTask();
+ task.execute(operation);
}
});
}
View
2  src/AndroidManifest.xml
@@ -3,5 +3,5 @@
package="com.microsoft.live"
android:versionCode="1"
android:versionName="1.0">
- <uses-sdk android:minSdkVersion="8" />
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="10"/>
</manifest>
View
89 src/internal/com/microsoft/live/ApiRequest.java
@@ -22,7 +22,6 @@
import org.json.JSONObject;
import android.net.Uri;
-import android.net.Uri.Builder;
import android.os.Build;
import android.text.TextUtils;
@@ -41,19 +40,27 @@
public enum Redirects {
SUPPRESS {
@Override
- protected void appendQueryParameter(Builder builder) {
- appendSuppressRedirects(builder, Boolean.TRUE);
+ protected void setQueryParameterOn(UriBuilder builder) {
+ Redirects.setQueryParameterOn(builder, Boolean.TRUE);
}
}, UNSUPPRESSED {
@Override
- protected void appendQueryParameter(Builder builder) {
- appendSuppressRedirects(builder, Boolean.FALSE);
+ protected void setQueryParameterOn(UriBuilder builder) {
+ Redirects.setQueryParameterOn(builder, Boolean.FALSE);
}
};
- protected abstract void appendQueryParameter(Uri.Builder builder);
-
- private static void appendSuppressRedirects(Uri.Builder builder, Boolean value) {
+ /**
+ * Sets the suppress_redirects query parameter by removing all existing ones
+ * and then appending it on the given UriBuilder.
+ */
+ protected abstract void setQueryParameterOn(UriBuilder builder);
+
+ private static void setQueryParameterOn(UriBuilder builder, Boolean value) {
+ // The Live SDK is designed to use our value of suppress_redirects.
+ // If it uses any other value it could cause issues. Remove any previously
+ // existing suppress_redirects and use ours.
+ builder.removeQueryParametersWithKey(QueryParameters.SUPPRESS_REDIRECTS);
builder.appendQueryParameter(QueryParameters.SUPPRESS_REDIRECTS, value.toString());
}
}
@@ -61,19 +68,27 @@ private static void appendSuppressRedirects(Uri.Builder builder, Boolean value)
public enum ResponseCodes {
SUPPRESS {
@Override
- protected void appendQueryParameter(Builder builder) {
- appendSuppressResponseCodes(builder, Boolean.TRUE);
+ protected void setQueryParameterOn(UriBuilder builder) {
+ ResponseCodes.setQueryParameterOn(builder, Boolean.TRUE);
}
}, UNSUPPRESSED {
@Override
- protected void appendQueryParameter(Builder builder) {
- appendSuppressResponseCodes(builder, Boolean.FALSE);
+ protected void setQueryParameterOn(UriBuilder builder) {
+ ResponseCodes.setQueryParameterOn(builder, Boolean.FALSE);
}
};
- protected abstract void appendQueryParameter(Uri.Builder builder);
-
- private static void appendSuppressResponseCodes(Uri.Builder builder, Boolean value) {
+ /**
+ * Sets the suppress_response_codes query parameter by removing all existing ones
+ * and then appending it on the given UriBuilder.
+ */
+ protected abstract void setQueryParameterOn(UriBuilder builder);
+
+ private static void setQueryParameterOn(UriBuilder builder, Boolean value) {
+ // The Live SDK is designed to use our value of suppress_response_codes.
+ // If it uses any other value it could cause issues. Remove any previously
+ // existing suppress_response_codes and use ours.
+ builder.removeQueryParametersWithKey(QueryParameters.SUPPRESS_RESPONSE_CODES);
builder.appendQueryParameter(QueryParameters.SUPPRESS_RESPONSE_CODES, value.toString());
}
}
@@ -105,7 +120,11 @@ private static Header createAuthroizationHeader(LiveConnectSession session) {
private final String path;
private final ResponseHandler<ResponseType> responseHandler;
private final LiveConnectSession session;
- protected final Uri.Builder requestUri;
+
+ protected final UriBuilder requestUri;
+
+ /** The original path string parsed into a Uri object. */
+ protected final Uri pathUri;
public ApiRequest(LiveConnectSession session,
HttpClient client,
@@ -139,36 +158,22 @@ public ApiRequest(LiveConnectSession session,
this.responseHandler = responseHandler;
this.path = path;
- Uri.Builder builder;
- Uri pathUri = Uri.parse(path);
- if (pathUri.isAbsolute()) {
- builder = pathUri.buildUpon();
- } else {
- builder = Config.INSTANCE.getApiUri()
- .buildUpon()
- .appendEncodedPath(pathUri.getPath())
- .encodedQuery(pathUri.getQuery());
- }
+ UriBuilder builder;
+ this.pathUri = Uri.parse(path);
- // we need to see if we have any extra query params
- // that need to be added on to the request uri
- String apiQuery = Config.INSTANCE.getApiUri().getEncodedQuery();
- String pathQuery = builder.build().getEncodedQuery();
- String query;
- if (apiQuery != null && pathQuery != null) {
- query = TextUtils.join("&", new String[]{apiQuery, pathQuery});
- } else if (apiQuery != null) {
- query = apiQuery;
- } else if (pathQuery != null) {
- query = pathQuery;
+ if (this.pathUri.isAbsolute()) {
+ // if the path is absolute we will just use that entire path
+ builder = UriBuilder.newInstance(this.pathUri);
} else {
- query = "";
+ // if it is a relative path then we should use the config's API URI,
+ // which is usually something like https://apis.live.net/v5.0
+ builder = UriBuilder.newInstance(Config.INSTANCE.getApiUri())
+ .appendToPath(this.pathUri.getEncodedPath())
+ .query(this.pathUri.getQuery());
}
- builder.encodedQuery(query);
-
- responseCodes.appendQueryParameter(builder);
- redirects.appendQueryParameter(builder);
+ responseCodes.setQueryParameterOn(builder);
+ redirects.setQueryParameterOn(builder);
this.requestUri = builder;
}
View
15 src/internal/com/microsoft/live/AuthorizationRequest.java
@@ -311,9 +311,8 @@ public void addObserver(OAuthRequestObserver observer) {
* passed in listener when it is completed.
*/
public void execute() {
- String displayType = OAuth.DisplayType.TOUCH.toString().toLowerCase();
+ String displayType = this.getDisplayParameter();
String responseType = OAuth.ResponseType.CODE.toString().toLowerCase();
- String theme = OAuth.ThemeType.DEFAULT.toString().toLowerCase();
String locale = Locale.getDefault().toString();
Uri requestUri = Config.INSTANCE.getOAuthAuthorizeUri()
.buildUpon()
@@ -322,7 +321,6 @@ public void execute() {
.appendQueryParameter(OAuth.DISPLAY, displayType)
.appendQueryParameter(OAuth.RESPONSE_TYPE, responseType)
.appendQueryParameter(OAuth.LOCALE, locale)
- .appendQueryParameter(OAuth.THEME, theme)
.appendQueryParameter(OAuth.REDIRECT_URI, this.redirectUri)
.build();
@@ -346,6 +344,17 @@ public boolean removeObserver(OAuthRequestObserver observer) {
}
/**
+ * Gets the display parameter by looking at the screen size of the activity.
+ * @return "android_phone" for phones and "android_tablet" for tablets.
+ */
+ private String getDisplayParameter() {
+ ScreenSize screenSize = ScreenSize.determineScreenSize(this.activity);
+ DeviceType deviceType = screenSize.getDeviceType();
+
+ return deviceType.getDisplayParameter().toString().toLowerCase();
+ }
+
+ /**
* Called when the response uri contains an access_token in the fragment.
*
* This method reads the response and calls back the LiveOAuthListener on the UI/main thread,
View
31 src/internal/com/microsoft/live/DeviceType.java
@@ -0,0 +1,31 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2012 Microsoft Corporation. All rights reserved.
+//
+// Description: See the class level JavaDoc comments.
+//------------------------------------------------------------------------------
+
+package com.microsoft.live;
+
+import com.microsoft.live.OAuth.DisplayType;
+
+/**
+ * The type of the device is used to determine the display query parameter for login.live.com.
+ * Phones have a display parameter of android_phone.
+ * Tablets have a display parameter of android_tablet.
+ */
+enum DeviceType {
+ PHONE {
+ @Override
+ public DisplayType getDisplayParameter() {
+ return DisplayType.ANDROID_PHONE;
+ }
+ },
+ TABLET {
+ @Override
+ public DisplayType getDisplayParameter() {
+ return DisplayType.ANDROID_TABLET;
+ }
+ };
+
+ abstract public DisplayType getDisplayParameter();
+}
View
15 src/internal/com/microsoft/live/OAuth.java
@@ -16,10 +16,8 @@
final class OAuth {
public enum DisplayType {
- NONE,
- PAGE,
- POPUP,
- TOUCH;
+ ANDROID_PHONE,
+ ANDROID_TABLET
}
public enum ErrorType {
@@ -86,15 +84,8 @@
TOKEN;
}
- public enum ThemeType {
- DARK,
- LIGHT,
- DEFAULT;
- }
-
public enum TokenType {
- BEARER,
- MAC;
+ BEARER
}
/**
View
73 src/internal/com/microsoft/live/ScreenSize.java
@@ -0,0 +1,73 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2012 Microsoft Corporation. All rights reserved.
+//
+// Description: See the class level JavaDoc comments.
+//------------------------------------------------------------------------------
+
+package com.microsoft.live;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.util.Log;
+
+/**
+ * The ScreenSize is used to determine the DeviceType.
+ * Small and Normal ScreenSizes are Phones.
+ * Large and XLarge are Tablets.
+ */
+enum ScreenSize {
+ SMALL {
+ @Override
+ public DeviceType getDeviceType() {
+ return DeviceType.PHONE;
+ }
+ },
+ NORMAL {
+ @Override
+ public DeviceType getDeviceType() {
+ return DeviceType.PHONE;
+ }
+
+ },
+ LARGE {
+ @Override
+ public DeviceType getDeviceType() {
+ return DeviceType.TABLET;
+ }
+ },
+ XLARGE {
+ @Override
+ public DeviceType getDeviceType() {
+ return DeviceType.TABLET;
+ }
+ };
+
+ public abstract DeviceType getDeviceType();
+
+ /**
+ * Configuration.SCREENLAYOUT_SIZE_XLARGE was not provided in API level 9.
+ * However, its value of 4 does show up.
+ */
+ private static final int SCREENLAYOUT_SIZE_XLARGE = 4;
+
+ public static ScreenSize determineScreenSize(Activity activity) {
+ int screenLayout = activity.getResources().getConfiguration().screenLayout;
+ int screenLayoutMasked = screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
+ switch (screenLayoutMasked) {
+ case Configuration.SCREENLAYOUT_SIZE_SMALL:
+ return SMALL;
+ case Configuration.SCREENLAYOUT_SIZE_NORMAL:
+ return NORMAL;
+ case Configuration.SCREENLAYOUT_SIZE_LARGE:
+ return LARGE;
+ case SCREENLAYOUT_SIZE_XLARGE:
+ return XLARGE;
+ default:
+ // If we cannot determine the ScreenSize, we'll guess and say it's normal.
+ Log.d(
+ "Live SDK ScreenSize",
+ "Unable to determine ScreenSize. A Normal ScreenSize will be returned.");
+ return NORMAL;
+ }
+ }
+}
View
24 src/internal/com/microsoft/live/UploadRequest.java
@@ -27,7 +27,6 @@
private HttpUriRequest currentRequest;
private final String filename;
- private final boolean isRelativePath;
/**
* true if the given path refers to a File Object
@@ -55,10 +54,8 @@ public UploadRequest(LiveConnectSession session,
this.filename = filename;
this.overwrite = overwrite;
- Uri uriPath = Uri.parse(path);
- this.isRelativePath = uriPath.isRelative();
- String lowerCasePath = uriPath.getPath().toLowerCase();
+ String lowerCasePath = this.pathUri.getPath().toLowerCase();
this.isFileUpload = lowerCasePath.indexOf(FILE_PATH) != -1;
}
@@ -69,11 +66,11 @@ public String getMethod() {
@Override
public JSONObject execute() throws LiveOperationException {
- Uri.Builder uploadRequestUri;
+ UriBuilder uploadRequestUri;
// if the path was relative, we have to retrieve the upload location, because if we don't,
// we will proxy the upload request, which is a waste of resources.
- if (this.isRelativePath) {
+ if (this.pathUri.isRelative()) {
JSONObject response = this.getUploadLocation();
// We could of tried to get the upload location on an invalid path.
@@ -94,7 +91,14 @@ public JSONObject execute() throws LiveOperationException {
throw new LiveOperationException(ErrorMessages.SERVER_ERROR, e);
}
- uploadRequestUri = Uri.parse(uploadLocation).buildUpon();
+ uploadRequestUri = UriBuilder.newInstance(Uri.parse(uploadLocation));
+
+ // The original path might have query parameters that were sent to the
+ // the upload location request, and those same query parameters will need
+ // to be sent to the HttpPut upload request too. Also, the returned upload_location
+ // *could* have query parameters on it. We want to keep those intact and in front of the
+ // the client's query parameters.
+ uploadRequestUri.appendQueryString(this.pathUri.getQuery());
} else {
uploadRequestUri = this.requestUri;
}
@@ -103,8 +107,8 @@ public JSONObject execute() throws LiveOperationException {
// if it is not a file upload it is a folder upload and we must
// add the file name to the upload location
// and don't forget to set the overwrite query parameter
- uploadRequestUri.appendPath(this.filename);
- this.overwrite.appendQueryParameter(uploadRequestUri);
+ uploadRequestUri.appendToPath(this.filename);
+ this.overwrite.appendQueryParameterOnTo(uploadRequestUri);
}
HttpPut uploadRequest = new HttpPut(uploadRequestUri.toString());
@@ -124,7 +128,7 @@ protected HttpUriRequest createHttpRequest() throws LiveOperationException {
* Performs an HttpGet on the folder/file object to retrieve the upload_location
*
* @return
- * @throws LiveOperationException
+ * @throws LiveOperationException if there was an error getting the getUploadLocation
*/
private JSONObject getUploadLocation() throws LiveOperationException {
this.currentRequest = new HttpGet(this.requestUri.toString());
View
277 src/internal/com/microsoft/live/UriBuilder.java
@@ -0,0 +1,277 @@
+//------------------------------------------------------------------------------
+// Copyright (c) 2012 Microsoft Corporation. All rights reserved.
+//
+// Description: See the class level JavaDoc comments.
+//------------------------------------------------------------------------------
+
+package com.microsoft.live;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Class for building URIs. The most useful benefit of this class is its query parameter
+ * management. It stores all the query parameters in a LinkedList, so parameters can
+ * be looked up, removed, and added easily.
+ */
+class UriBuilder {
+
+ public static class QueryParameter {
+ private final String key;
+ private final String value;
+
+ /**
+ * Constructs a query parameter with no value (e.g., download).
+ *
+ * @param key
+ */
+ public QueryParameter(String key) {
+ assert key != null;
+
+ this.key = key;
+ this.value = null;
+ }
+
+ public QueryParameter(String key, String value) {
+ assert key != null;
+ assert value != null;
+
+ this.key = key;
+ this.value = value;
+ }
+
+ public String getKey() {
+ return this.key;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+
+ public boolean hasValue() {
+ return this.value != null;
+ }
+
+ @Override
+ public String toString() {
+ if (this.hasValue()) {
+ return this.key + "=" + this.value;
+ }
+
+ return this.key;
+ }
+ }
+
+ private static final String EQUAL = "=";
+ private static final String AMPERSAND = "&";
+ private static final char FORWARD_SLASH = '/';
+
+ private String scheme;
+ private String host;
+ private StringBuilder path;
+
+ private final LinkedList<QueryParameter> queryParameters;
+
+ /**
+ * Constructs a new UriBuilder from the given Uri.
+ *
+ * @return a new Uri Builder based off the given Uri.
+ */
+ public static UriBuilder newInstance(Uri uri) {
+ return new UriBuilder().scheme(uri.getScheme())
+ .host(uri.getHost())
+ .path(uri.getPath())
+ .query(uri.getQuery());
+ }
+
+ public UriBuilder() {
+ this.queryParameters = new LinkedList<QueryParameter>();
+ }
+
+ /**
+ * Appends a new query parameter to the UriBuilder's query string.
+ *
+ * (e.g., appendQueryParameter("k1", "v1") when UriBuilder's query string is
+ * k2=v2&k3=v3 results in k2=v2&k3=v3&k1=v1).
+ *
+ * @param key Key of the new query parameter.
+ * @param value Value of the new query parameter.
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder appendQueryParameter(String key, String value) {
+ assert key != null;
+ assert value != null;
+
+ this.queryParameters.add(new QueryParameter(key, value));
+
+ return this;
+ }
+
+ /**
+ * Appends the given query string on to the existing UriBuilder's query parameters.
+ *
+ * (e.g., UriBuilder's queryString k1=v1&k2=v2 and given queryString k3=v3&k4=v4, results in
+ * k1=v1&k2=v2&k3=v3&k4=v4).
+ *
+ * @param queryString Key-Value pairs separated by & and = (e.g., k1=v1&k2=v2&k3=k3).
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder appendQueryString(String queryString) {
+ if (queryString == null) {
+ return this;
+ }
+
+ String[] pairs = TextUtils.split(queryString, UriBuilder.AMPERSAND);
+ for(String pair : pairs) {
+ String[] splitPair = TextUtils.split(pair, UriBuilder.EQUAL);
+ if (splitPair.length == 2) {
+ String key = splitPair[0];
+ String value = splitPair[1];
+
+ this.queryParameters.add(new QueryParameter(key, value));
+ } else if (splitPair.length == 1){
+ String key = splitPair[0];
+
+ this.queryParameters.add(new QueryParameter(key));
+ } else {
+ Log.w("com.microsoft.live.UriBuilder", "Invalid query parameter: " + pair);
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Appends the given path to the UriBuilder's current path.
+ *
+ * @param path The path to append onto this UriBuilder's path.
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder appendToPath(String path) {
+ assert path != null;
+
+ if (this.path == null) {
+ this.path = new StringBuilder(path);
+ } else {
+ boolean endsWithSlash = TextUtils.isEmpty(this.path) ? false :
+ this.path.charAt(this.path.length() - 1) == UriBuilder.FORWARD_SLASH;
+ boolean pathIsEmpty = TextUtils.isEmpty(path);
+ boolean beginsWithSlash =
+ pathIsEmpty ? false : path.charAt(0) == UriBuilder.FORWARD_SLASH;
+
+ if (endsWithSlash && beginsWithSlash) {
+ if (path.length() > 1) {
+ this.path.append(path.substring(1));
+
+ }
+ } else if (!endsWithSlash && !beginsWithSlash) {
+ if (!pathIsEmpty) {
+ this.path.append(UriBuilder.FORWARD_SLASH).append(path);
+ }
+ } else {
+ this.path.append(path);
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Builds the Uri by converting into a android.net.Uri object.
+ *
+ * @return a new android.net.Uri defined by what was given to the builder.
+ */
+ public Uri build() {
+ return new Uri.Builder().scheme(this.scheme)
+ .authority(this.host)
+ .path(this.path == null ? "" : this.path.toString())
+ .encodedQuery(TextUtils.join("&", this.queryParameters))
+ .build();
+ }
+
+ /**
+ * Sets the host part of the Uri.
+ *
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder host(String host) {
+ assert host != null;
+ this.host = host;
+
+ return this;
+ }
+
+ /**
+ * Sets the path and removes any previously existing path.
+ *
+ * @param path The path to set on this UriBuilder.
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder path(String path) {
+ assert path != null;
+ this.path = new StringBuilder(path);
+
+ return this;
+ }
+
+ /**
+ * Takes a query string and puts it in the Uri Builder's query string removing
+ * any existing query parameters.
+ *
+ * @param queryString Key-Value pairs separated by & and = (e.g., k1=v1&k2=v2&k3=k3).
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder query(String queryString) {
+ this.queryParameters.clear();
+
+ return this.appendQueryString(queryString);
+ }
+
+ /**
+ * Removes all query parameters from the UriBuilder that has the given key.
+ *
+ * (e.g., removeQueryParametersWithKey("k1") when UriBuilder's query string of k1=v1&k2=v2&k1=v3
+ * results in k2=v2).
+ *
+ * @param key Query parameter's key to remove
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder removeQueryParametersWithKey(String key) {
+ // There could be multiple query parameters with this key and
+ // we want to remove all of them.
+ Iterator<QueryParameter> it = this.queryParameters.iterator();
+
+ while (it.hasNext()) {
+ QueryParameter qp = it.next();
+ if (qp.getKey().equals(key)) {
+ it.remove();
+ }
+ }
+
+ return this;
+ }
+
+ /**
+ * Sets the scheme part of the Uri.
+ *
+ * @return this UriBuilder object. Useful for chaining.
+ */
+ public UriBuilder scheme(String scheme) {
+ assert scheme != null;
+ this.scheme = scheme;
+
+ return this;
+ }
+
+ /**
+ * Returns the URI in string format (e.g., http://foo.com/bar?k1=v2).
+ */
+ @Override
+ public String toString() {
+ return this.build().toString();
+ }
+}
View
8 src/src/com/microsoft/live/OverwriteOption.java
@@ -6,8 +6,6 @@
package com.microsoft.live;
-import android.net.Uri.Builder;
-
/**
* Enum that specifies what to do during a naming conflict during an upload.
*/
@@ -37,7 +35,11 @@ protected String overwriteQueryParamValue() {
}
};
- void appendQueryParameter(Builder uri) {
+ /**
+ * Leaves any existing overwrite query parameter on appends this overwrite
+ * to the given UriBuilder.
+ */
+ void appendQueryParameterOnTo(UriBuilder uri) {
uri.appendQueryParameter(QueryParameters.OVERWRITE, this.overwriteQueryParamValue());
}
View
12 unittest/src/com/microsoft/live/TestUtils.java
@@ -15,14 +15,17 @@
*/
public final class TestUtils {
- public static LiveConnectClient newLiveConnectClient(HttpClient client) {
- LiveAuthClient authClient = new LiveAuthClient(new MockApplication() {
+ public static LiveAuthClient newMockLiveAuthClient() {
+ return new LiveAuthClient(new MockApplication() {
@Override
public Context getApplicationContext() {
return this;
}
}, "someclientid");
+ }
+ public static LiveConnectSession newMockLiveConnectSession() {
+ LiveAuthClient authClient = TestUtils.newMockLiveAuthClient();
LiveConnectSession session = new LiveConnectSession(authClient);
session.setAccessToken("access_token");
session.setAuthenticationToken("authentication_token");
@@ -36,6 +39,11 @@ public Context getApplicationContext() {
session.setRefreshToken("refresh_token");
session.setTokenType("token_type");
+ return session;
+ }
+
+ public static LiveConnectClient newLiveConnectClient(HttpClient client) {
+ LiveConnectSession session = TestUtils.newMockLiveConnectSession();
LiveConnectClient liveClient = new LiveConnectClient(session);
liveClient.setHttpClient(client);
View
122 unittest/src/com/microsoft/live/UploadRequestTest.java
@@ -0,0 +1,122 @@
+package com.microsoft.live;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.message.BasicStatusLine;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpContext;
+import org.json.JSONObject;
+
+import com.microsoft.live.constants.JsonKeys;
+import com.microsoft.live.constants.Paths;
+import com.microsoft.live.mock.MockHttpEntity;
+import com.microsoft.live.mock.MockHttpResponse;
+
+import android.test.InstrumentationTestCase;
+
+public class UploadRequestTest extends InstrumentationTestCase {
+
+ /**
+ * WinLive 633441: Make sure the query parameters on path get sent to
+ * the HTTP PUT part of the upload.
+ */
+ public void testSendPathQueryParameterToHttpPut() throws Throwable {
+ JSONObject jsonResponseBody = new JSONObject();
+ jsonResponseBody.put(JsonKeys.UPLOAD_LOCATION, "http://test.com/location");
+ InputStream responseStream =
+ new ByteArrayInputStream(jsonResponseBody.toString().getBytes());
+ MockHttpEntity responseEntity = new MockHttpEntity(responseStream);
+ BasicStatusLine ok = new BasicStatusLine(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "");
+ final MockHttpResponse uploadLocationResponse = new MockHttpResponse(responseEntity, ok);
+
+ HttpClient client = new HttpClient() {
+ /** the first request to the client is the upload location request. */
+ boolean uploadLocationRequest = true;
+
+ @Override
+ public HttpResponse execute(HttpUriRequest request)
+ throws IOException, ClientProtocolException {
+
+ if (uploadLocationRequest) {
+ uploadLocationRequest = false;
+ return uploadLocationResponse;
+ }
+
+ // This is really the only part we care about in this test.
+ // That the 2nd request's uri has foo=bar in the query string.
+ URI uri = request.getURI();
+ assertEquals("foo=bar&overwrite=choosenewname", uri.getQuery());
+
+ // for the test it doesn't matter what it contains, as long as it has valid json.
+ // just return the previous reponse.
+ return uploadLocationResponse;
+ }
+
+ @Override
+ public HttpResponse execute(HttpUriRequest request, HttpContext context) throws IOException, ClientProtocolException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public HttpResponse execute(HttpHost target, HttpRequest request) throws IOException, ClientProtocolException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpUriRequest arg0, ResponseHandler<? extends T> arg1) throws IOException, ClientProtocolException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) throws IOException, ClientProtocolException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpUriRequest arg0, ResponseHandler<? extends T> arg1, HttpContext arg2) throws IOException, ClientProtocolException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpHost arg0, HttpRequest arg1, ResponseHandler<? extends T> arg2) throws IOException, ClientProtocolException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> T execute(HttpHost arg0, HttpRequest arg1, ResponseHandler<? extends T> arg2, HttpContext arg3) throws IOException, ClientProtocolException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ClientConnectionManager getConnectionManager() { throw new UnsupportedOperationException(); }
+
+ @Override
+ public HttpParams getParams() { throw new UnsupportedOperationException(); }
+ };
+
+ LiveConnectSession session = TestUtils.newMockLiveConnectSession();
+
+ HttpEntity entity = new MockHttpEntity();
+ String path = Paths.ME_SKYDRIVE + "?foo=bar";
+ String filename = "filename";
+
+ UploadRequest uploadRequest =
+ new UploadRequest(session, client, path, entity, filename, OverwriteOption.Rename);
+
+ uploadRequest.execute();
+ }
+}
View
294 unittest/src/com/microsoft/live/UriBuilderTest.java
@@ -0,0 +1,294 @@
+package com.microsoft.live;
+
+import android.test.InstrumentationTestCase;
+
+public class UriBuilderTest extends InstrumentationTestCase {
+
+ public void testAppendEmptyPath() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.path("bar");
+ builder.appendToPath("");
+
+ assertEquals("http://foo.com/bar", builder.toString());
+ }
+
+ public void testEmptyPathEmptyAppendPath() {
+ UriBuilder builder = new UriBuilder();
+
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.path("");
+ builder.appendToPath("");
+
+ assertEquals("http://foo.com", builder.toString());
+ }
+
+ public void testAppendSingleForwardSlash() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.path("bar");
+ builder.appendToPath("/");
+
+ assertEquals("http://foo.com/bar/", builder.toString());
+ }
+
+ public void testAppendOnToPathThatEndsInSlash() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.path("bar/");
+ builder.appendToPath("test");
+
+ assertEquals("http://foo.com/bar/test", builder.toString());
+ }
+
+ public void testAppendPathThatBeginsWithSlashOnToPathThatEndsInSlash() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.path("bar/");
+ builder.appendToPath("/test");
+
+ assertEquals("http://foo.com/bar/test", builder.toString());
+ }
+
+ public void testSetQueryWithNullQueryString() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query(null);
+
+ assertEquals("http://foo.com", builder.toString());
+ }
+
+ public void testSetQueryWithDuplicates() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k2=v2&k1=v1");
+
+ assertEquals("http://foo.com?k1=v1&k2=v2&k1=v1", builder.toString());
+ }
+
+ /**
+ * Storage returns URLs with a query parameter that has no value.
+ */
+ public void testSetQueryWithKeyAndNoValue() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.query("download");
+
+ assertEquals("http://foo.com?download", builder.toString());
+ }
+
+ public void testSetQueryWithEmptyString() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.query("");
+
+ assertEquals("http://foo.com", builder.toString());
+ }
+
+ public void testSetQueryStringOnePair() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.query("k1=v1");
+
+ assertEquals("http://foo.com?k1=v1", builder.toString());
+ }
+
+ public void testSetQueryStringMultiplePairs() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.query("k1=v1&k2=v2");
+
+ assertEquals("http://foo.com?k1=v1&k2=v2", builder.toString());
+ }
+
+ public void testSetQueryStringRemoveExisting() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k2=v2");
+ builder.query("k1=v1");
+
+ int indexOfQuestionMark = builder.toString().indexOf("?");
+ String queryString = builder.toString().substring(indexOfQuestionMark + 1);
+
+ assertEquals("k1=v1", queryString);
+ }
+
+ public void testRemoveQueryParametersExistingKey() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k2=v2&k3=v3");
+
+ builder.removeQueryParametersWithKey("k2");
+
+ assertEquals("http://foo.com?k1=v1&k3=v3", builder.toString());
+ }
+
+ public void testRemoveQueryParametersWithNoValue() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k2&k3=v3");
+
+ builder.removeQueryParametersWithKey("k2");
+
+ assertEquals("http://foo.com?k1=v1&k3=v3", builder.toString());
+ }
+
+ public void testRemoveQueryParametersDoesNotExist() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k2=v2&k3=v3");
+
+ builder.removeQueryParametersWithKey("k4");
+
+ assertEquals("http://foo.com?k1=v1&k2=v2&k3=v3", builder.toString());
+ }
+
+ public void testRemoveQueryParametersNullKey() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k2=v2&k3=v3");
+
+ builder.removeQueryParametersWithKey(null);
+
+ assertEquals("http://foo.com?k1=v1&k2=v2&k3=v3", builder.toString());
+ }
+
+ public void testRemoveQueryParametersEmptyStringKey() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k2=v2&k3=v3");
+
+ builder.removeQueryParametersWithKey("");
+
+ assertEquals("http://foo.com?k1=v1&k2=v2&k3=v3", builder.toString());
+ }
+
+ public void testRemoveQueryParametersMultipleKeys() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k1=v2&k3=v3");
+
+ builder.removeQueryParametersWithKey("k1");
+
+ assertEquals("http://foo.com?k3=v3", builder.toString());
+ }
+
+ public void testRemoveQueryParametersAll() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1&k2=v2&k3=v3");
+
+ builder.removeQueryParametersWithKey("k1");
+ builder.removeQueryParametersWithKey("k2");
+ builder.removeQueryParametersWithKey("k3");
+
+ assertEquals("http://foo.com", builder.toString());
+ }
+
+ public void testRemoveQueryParametersFromNoQueryParameters() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.removeQueryParametersWithKey("k1");
+
+ assertEquals("http://foo.com", builder.toString());
+ }
+
+ public void testAppendQueryParameterOnNoExistingQueryString() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.appendQueryParameter("k1", "v1");
+
+ assertEquals("http://foo.com?k1=v1", builder.toString());
+ }
+
+ public void testAppendQueryParameterOnExistingQueryString() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1");
+
+ builder.appendQueryParameter("k2", "v2");
+
+ assertEquals("http://foo.com?k1=v1&k2=v2", builder.toString());
+ }
+
+ public void testAppendQueryParameterCreateDuplicates() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1");
+
+ builder.appendQueryParameter("k1", "v1");
+
+ assertEquals("http://foo.com?k1=v1&k1=v1", builder.toString());
+ }
+
+ public void testAppendQueryStringMultipleParameters() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.appendQueryString("k1=v1&k2=v2");
+
+ assertEquals("http://foo.com?k1=v1&k2=v2", builder.toString());
+ }
+
+ public void testAppendQueryStringOnNoExistingQueryString() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+
+ builder.appendQueryString("k1=v1");
+
+ assertEquals("http://foo.com?k1=v1", builder.toString());
+ }
+
+ public void testAppendQueryStringOnExistingQueryString() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1");
+
+ builder.appendQueryString("k2=v2");
+
+ assertEquals("http://foo.com?k1=v1&k2=v2", builder.toString());
+ }
+
+ public void testAppendQueryStringCreateDuplicates() {
+ UriBuilder builder = new UriBuilder();
+ builder.scheme("http");
+ builder.host("foo.com");
+ builder.query("k1=v1");
+
+ builder.appendQueryString("k1=v1");
+
+ assertEquals("http://foo.com?k1=v1&k1=v1", builder.toString());
+ }
+}
View
1  unittest/src/com/microsoft/live/unittest/UploadTest.java
@@ -38,7 +38,6 @@
FILE = new ByteArrayInputStream("File contents".getBytes());
}
-
public void testAsyncFileNull() {
try {
this.liveConnectClient.uploadAsync(Paths.ME_SKYDRIVE,
View
17 utilities/src/com/microsoft/live/constants/ErrorMessages.java
@@ -3,23 +3,22 @@
public final class ErrorMessages {
public static final String MISSING_REQUIRED_PARAMETER =
- "The provided request entity body is missing a required parameter. " +
- "The request must include at least one of the following: %1$s.";
+ "The request entity body is missing a required parameter. " +
+ "The request must include at least one of these parameters: %1$s.";
public static final String MISSING_REQUIRED_PARAMETER_2 =
- "The provided request entity body is missing a required parameter %1$s. " +
- "Required parameters are the following: %1$s.";
+ "The request entity body is missing the required parameter: %1$s. " +
+ "Required parameters include: %1$s.";
public static final String PARAMETER_NOT_VALID =
- "The provided value for the input resource ID parameter '%s' is not valid. " +
- "Expected value is a resource ID for one of the following types: %s.";
+ "The value of input resource ID parameter '%s' isn't valid. " +
+ "The expected value for this parameter is a resource ID for one of these types: %s.";
public static final String RESOURCE_DOES_NOT_EXIST =
- "The requested resource '%s' does not exist.";
+ "The resource '%s' doesn't exist.";
public static final String URL_NOT_VALID =
- "The provided URL is not valid. The requested path '%s' is not supported.";
-
+ "The URL contains the path '%s', which isn't supported.";
private ErrorMessages() { throw new AssertionError(); }
}
Please sign in to comment.
Something went wrong with that request. Please try again.