/* * Copyright 2010 Mark Wyszomierski * Portions Copyright (c) 2008-2010 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.facebook.android; import android.os.Bundle; import android.text.TextUtils; import java.io.IOException; import java.net.MalformedURLException; /** * Main Facebook object for storing session token and session expiration date * in memory, as well as generating urls to access different facebook endpoints. * * @author Steven Soneff (ssoneff@facebook.com): * -original author. * @author Mark Wyszomierski (markww@gmail.com): * -modified to remove network operation calls, and dialog creation, * focused on making this class only generate urls for external use * and storage of a session token and expiration date. */ public class Facebook { /** Strings used in the OAuth flow */ public static final String REDIRECT_URI = "fbconnect://success"; public static final String CANCEL_URI = "fbconnect:cancel"; public static final String TOKEN = "access_token"; public static final String EXPIRES = "expires_in"; /** Login action requires a few extra steps for setup and completion. */ public static final String LOGIN = "login"; /** Facebook server endpoints: may be modified in a subclass for testing */ protected static String OAUTH_ENDPOINT = "https://graph.facebook.com/oauth/authorize"; // https protected static String UI_SERVER = "http://www.facebook.com/connect/uiserver.php"; // http protected static String GRAPH_BASE_URL = "https://graph.facebook.com/"; protected static String RESTSERVER_URL = "https://api.facebook.com/restserver.php"; private String mAccessToken = null; private long mAccessExpires = 0; public Facebook() { } /** * Invalidates the current access token in memory, and generates a * prepared URL that can be used to log the user out. * * @throws MalformedURLException * @return PreparedUrl instance reflecting the full url of the service. */ public PreparedUrl logout() throws MalformedURLException, IOException { setAccessToken(null); setAccessExpires(0); Bundle b = new Bundle(); b.putString("method", "auth.expireSession"); return requestUrl(b); } /** * Build a url to Facebook's old (pre-graph) API with the given * parameters. One of the parameter keys must be "method" and its value * should be a valid REST server API method. * * See http://developers.facebook.com/docs/reference/rest/ * * Example: * <code> * Bundle parameters = new Bundle(); * parameters.putString("method", "auth.expireSession"); * PreparedUrl preparedUrl = requestUrl(parameters); * </code> * * @param parameters * Key-value pairs of parameters to the request. Refer to the * documentation: one of the parameters must be "method". * @throws MalformedURLException * if accessing an invalid endpoint * @throws IllegalArgumentException * if one of the parameters is not "method" * @return PreparedUrl instance reflecting the full url of the service. */ public PreparedUrl requestUrl(Bundle parameters) throws MalformedURLException { if (!parameters.containsKey("method")) { throw new IllegalArgumentException("API method must be specified. " + "(parameters must contain key \"method\" and value). See" + " http://developers.facebook.com/docs/reference/rest/"); } return requestUrl(null, parameters, "GET"); } /** * Build a url to the Facebook Graph API without any parameters. * * See http://developers.facebook.com/docs/api * * @param graphPath * Path to resource in the Facebook graph, e.g., to fetch data * about the currently logged authenticated user, provide "me", * which will fetch http://graph.facebook.com/me * @throws MalformedURLException * @return PreparedUrl instance reflecting the full url of the service. */ public PreparedUrl requestUrl(String graphPath) throws MalformedURLException { return requestUrl(graphPath, new Bundle(), "GET"); } /** * Build a url to the Facebook Graph API with the given string * parameters using an HTTP GET (default method). * * See http://developers.facebook.com/docs/api * * @param graphPath * Path to resource in the Facebook graph, e.g., to fetch data * about the currently logged authenticated user, provide "me", * which will fetch http://graph.facebook.com/me * @param parameters * key-value string parameters, e.g. the path "search" with * parameters "q" : "facebook" would produce a query for the * following graph resource: * https://graph.facebook.com/search?q=facebook * @throws MalformedURLException * @return PreparedUrl instance reflecting the full url of the service. */ public PreparedUrl requestUrl(String graphPath, Bundle parameters) throws MalformedURLException { return requestUrl(graphPath, parameters, "GET"); } /** * Build a PreparedUrl object which can be used with Util.openUrl(). * You can also use the returned PreparedUrl.getUrl() to run the * network operation yourself. * * Note that binary data parameters * (e.g. pictures) are not yet supported by this helper function. * * See http://developers.facebook.com/docs/api * * @param graphPath * Path to resource in the Facebook graph, e.g., to fetch data * about the currently logged authenticated user, provide "me", * which will fetch http://graph.facebook.com/me * @param parameters * key-value string parameters, e.g. the path "search" with * parameters {"q" : "facebook"} would produce a query for the * following graph resource: * https://graph.facebook.com/search?q=facebook * @param httpMethod * http verb, e.g. "GET", "POST", "DELETE" * @throws MalformedURLException * @return PreparedUrl instance reflecting the full url of the service. */ public PreparedUrl requestUrl(String graphPath, Bundle parameters, String httpMethod) throws MalformedURLException { parameters.putString("format", "json"); if (isSessionValid()) { parameters.putString(TOKEN, getAccessToken()); } String url = graphPath != null ? GRAPH_BASE_URL + graphPath : RESTSERVER_URL; return new PreparedUrl(url, parameters, httpMethod); } public boolean isSessionValid() { return (getAccessToken() != null) && ((getAccessExpires() == 0) || (System.currentTimeMillis() < getAccessExpires())); } public String getAccessToken() { return mAccessToken; } public long getAccessExpires() { return mAccessExpires; } public void setAccessToken(String token) { mAccessToken = token; } public void setAccessExpires(long time) { mAccessExpires = time; } public void setAccessExpiresIn(String expiresIn) { if (expiresIn != null) { setAccessExpires(System.currentTimeMillis() + Integer.parseInt(expiresIn) * 1000); } } public String generateUrl(String action, String appId, String[] permissions) { Bundle params = new Bundle(); String endpoint; if (action.equals(LOGIN)) { params.putString("client_id", appId); if (permissions != null && permissions.length > 0) { params.putString("scope", TextUtils.join(",", permissions)); } endpoint = OAUTH_ENDPOINT; params.putString("type", "user_agent"); params.putString("redirect_uri", REDIRECT_URI); } else { endpoint = UI_SERVER; params.putString("method", action); params.putString("next", REDIRECT_URI); } params.putString("display", "touch"); params.putString("sdk", "android"); if (isSessionValid()) { params.putString(TOKEN, getAccessToken()); } String url = endpoint + "?" + FacebookUtil.encodeUrl(params); return url; } /** * Stores a prepared url and parameters bundle from one of the <code>requestUrl</code> * methods. It can then be used with Util.openUrl() to run the network operation. * The Util.openUrl() requires the original params bundle and http method, so this * is just a convenience wrapper around it. * * @author Mark Wyszomierski (markww@gmail.com) */ public static class PreparedUrl { private String mUrl; private Bundle mParameters; private String mHttpMethod; public PreparedUrl(String url, Bundle parameters, String httpMethod) { mUrl = url; mParameters = parameters; mHttpMethod = httpMethod; } public String getUrl() { return mUrl; } public Bundle getParameters() { return mParameters; } public String getHttpMethod() { return mHttpMethod; } } }