Blame | Last modification | View Log | RSS feed
/*** Copyright 2010-present Facebook** 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.Manifest;import android.app.Activity;import android.content.*;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.content.pm.PackageManager.NameNotFoundException;import android.content.pm.ResolveInfo;import android.content.pm.Signature;import android.net.Uri;import android.os.*;import com.facebook.*;import com.facebook.Session.StatusCallback;import java.io.FileNotFoundException;import java.io.IOException;import java.lang.ref.WeakReference;import java.net.MalformedURLException;import java.util.Arrays;import java.util.Collections;import java.util.List;/*** THIS CLASS SHOULD BE CONSIDERED DEPRECATED.* <p/>* All public members of this class are intentionally deprecated.* New code should instead use* {@link Session} to manage session state,* {@link Request} to make API requests, and* {@link com.facebook.widget.WebDialog} to make dialog requests.* <p/>* Adding @Deprecated to this class causes warnings in other deprecated classes* that reference this one. That is the only reason this entire class is not* deprecated.** @devDocDeprecated*/public class Facebook {// Strings used in the authorization flow@Deprecatedpublic static final String REDIRECT_URI = "fbconnect://success";@Deprecatedpublic static final String CANCEL_URI = "fbconnect://cancel";@Deprecatedpublic static final String TOKEN = "access_token";@Deprecatedpublic static final String EXPIRES = "expires_in";@Deprecatedpublic static final String SINGLE_SIGN_ON_DISABLED = "service_disabled";@Deprecatedpublic static final Uri ATTRIBUTION_ID_CONTENT_URI =Uri.parse("content://com.facebook.katana.provider.AttributionIdProvider");@Deprecatedpublic static final String ATTRIBUTION_ID_COLUMN_NAME = "aid";@Deprecatedpublic static final int FORCE_DIALOG_AUTH = -1;private static final String LOGIN = "oauth";// Used as default activityCode by authorize(). See authorize() below.private static final int DEFAULT_AUTH_ACTIVITY_CODE = 32665;// Facebook server endpoints: may be modified in a subclass for testing@Deprecatedprotected static String DIALOG_BASE_URL = "https://m.facebook.com/dialog/";@Deprecatedprotected static String GRAPH_BASE_URL = "https://graph.facebook.com/";@Deprecatedprotected static String RESTSERVER_URL = "https://api.facebook.com/restserver.php";private final Object lock = new Object();private String accessToken = null;private long accessExpiresMillisecondsAfterEpoch = 0;private long lastAccessUpdateMillisecondsAfterEpoch = 0;private String mAppId;private Activity pendingAuthorizationActivity;private String[] pendingAuthorizationPermissions;private Session pendingOpeningSession;private volatile Session session; // must synchronize this.sync to writeprivate boolean sessionInvalidated; // must synchronize this.sync to accessprivate SetterTokenCachingStrategy tokenCache;private volatile Session userSetSession;// If the last time we extended the access token was more than 24 hours ago// we try to refresh the access token again.final private static long REFRESH_TOKEN_BARRIER = 24L * 60L * 60L * 1000L;/*** Constructor for Facebook object.** @param appId* Your Facebook application ID. Found at* www.facebook.com/developers/apps.php.*/@Deprecatedpublic Facebook(String appId) {if (appId == null) {throw new IllegalArgumentException("You must specify your application ID when instantiating "+ "a Facebook object. See README for details.");}mAppId = appId;}/*** Default authorize method. Grants only basic permissions.* <p/>* See authorize() below for @params.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.*/@Deprecatedpublic void authorize(Activity activity, final DialogListener listener) {authorize(activity, new String[]{}, DEFAULT_AUTH_ACTIVITY_CODE, SessionLoginBehavior.SSO_WITH_FALLBACK,listener);}/*** Authorize method that grants custom permissions.* <p/>* See authorize() below for @params.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.*/@Deprecatedpublic void authorize(Activity activity, String[] permissions, final DialogListener listener) {authorize(activity, permissions, DEFAULT_AUTH_ACTIVITY_CODE, SessionLoginBehavior.SSO_WITH_FALLBACK, listener);}/*** Full authorize method.* <p/>* Starts either an Activity or a dialog which prompts the user to log in to* Facebook and grant the requested permissions to the given application.* <p/>* This method will, when possible, use Facebook's single sign-on for* Android to obtain an access token. This involves proxying a call through* the Facebook for Android stand-alone application, which will handle the* authentication flow, and return an OAuth access token for making API* calls.* <p/>* Because this process will not be available for all users, if single* sign-on is not possible, this method will automatically fall back to the* OAuth 2.0 User-Agent flow. In this flow, the user credentials are handled* by Facebook in an embedded WebView, not by the client application. As* such, the dialog makes a network request and renders HTML content rather* than a native UI. The access token is retrieved from a redirect to a* special URL that the WebView handles.* <p/>* Note that User credentials could be handled natively using the OAuth 2.0* Username and Password Flow, but this is not supported by this SDK.* <p/>* See http://developers.facebook.com/docs/authentication/ and* http://wiki.oauth.net/OAuth-2 for more details.* <p/>* Note that this method is asynchronous and the callback will be invoked in* the original calling thread (not in a background thread).* <p/>* Also note that requests may be made to the API without calling authorize* first, in which case only public information is returned.* <p/>* IMPORTANT: Note that single sign-on authentication will not function* correctly if you do not include a call to the authorizeCallback() method* in your onActivityResult() function! Please see below for more* information. single sign-on may be disabled by passing FORCE_DIALOG_AUTH* as the activityCode parameter in your call to authorize().* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param activity* The Android activity in which we want to display the* authorization dialog.* @param permissions* A list of permissions required for this application: e.g.* "read_stream", "publish_stream", "offline_access", etc. see* http://developers.facebook.com/docs/authentication/permissions* This parameter should not be null -- if you do not require any* permissions, then pass in an empty String array.* @param activityCode* Single sign-on requires an activity result to be called back* to the client application -- if you are waiting on other* activities to return data, pass a custom activity code here to* avoid collisions. If you would like to force the use of legacy* dialog-based authorization, pass FORCE_DIALOG_AUTH for this* parameter. Otherwise just omit this parameter and Facebook* will use a suitable default. See* http://developer.android.com/reference/android/* app/Activity.html for more information.* @param listener* Callback interface for notifying the calling application when* the authentication dialog has completed, failed, or been* canceled.*/@Deprecatedpublic void authorize(Activity activity, String[] permissions, int activityCode, final DialogListener listener) {SessionLoginBehavior behavior = (activityCode >= 0) ? SessionLoginBehavior.SSO_WITH_FALLBACK: SessionLoginBehavior.SUPPRESS_SSO;authorize(activity, permissions, activityCode, behavior, listener);}/*** Full authorize method.** Starts either an Activity or a dialog which prompts the user to log in to* Facebook and grant the requested permissions to the given application.** This method will, when possible, use Facebook's single sign-on for* Android to obtain an access token. This involves proxying a call through* the Facebook for Android stand-alone application, which will handle the* authentication flow, and return an OAuth access token for making API* calls.** Because this process will not be available for all users, if single* sign-on is not possible, this method will automatically fall back to the* OAuth 2.0 User-Agent flow. In this flow, the user credentials are handled* by Facebook in an embedded WebView, not by the client application. As* such, the dialog makes a network request and renders HTML content rather* than a native UI. The access token is retrieved from a redirect to a* special URL that the WebView handles.** Note that User credentials could be handled natively using the OAuth 2.0* Username and Password Flow, but this is not supported by this SDK.** See http://developers.facebook.com/docs/authentication/ and* http://wiki.oauth.net/OAuth-2 for more details.** Note that this method is asynchronous and the callback will be invoked in* the original calling thread (not in a background thread).** Also note that requests may be made to the API without calling authorize* first, in which case only public information is returned.** IMPORTANT: Note that single sign-on authentication will not function* correctly if you do not include a call to the authorizeCallback() method* in your onActivityResult() function! Please see below for more* information. single sign-on may be disabled by passing FORCE_DIALOG_AUTH* as the activityCode parameter in your call to authorize().** @param activity* The Android activity in which we want to display the* authorization dialog.* @param permissions* A list of permissions required for this application: e.g.* "read_stream", "publish_stream", "offline_access", etc. see* http://developers.facebook.com/docs/authentication/permissions* This parameter should not be null -- if you do not require any* permissions, then pass in an empty String array.* @param activityCode* Single sign-on requires an activity result to be called back* to the client application -- if you are waiting on other* activities to return data, pass a custom activity code here to* avoid collisions. If you would like to force the use of legacy* dialog-based authorization, pass FORCE_DIALOG_AUTH for this* parameter. Otherwise just omit this parameter and Facebook* will use a suitable default. See* http://developer.android.com/reference/android/* app/Activity.html for more information.* @param behavior* The {@link SessionLoginBehavior SessionLoginBehavior} that* specifies what behaviors should be attempted during* authorization.* @param listener* Callback interface for notifying the calling application when* the authentication dialog has completed, failed, or been* canceled.*/private void authorize(Activity activity, String[] permissions, int activityCode,SessionLoginBehavior behavior, final DialogListener listener) {checkUserSession("authorize");pendingOpeningSession = new Session.Builder(activity).setApplicationId(mAppId).setTokenCachingStrategy(getTokenCache()).build();pendingAuthorizationActivity = activity;pendingAuthorizationPermissions = (permissions != null) ? permissions : new String[0];StatusCallback callback = new StatusCallback() {@Overridepublic void call(Session callbackSession, SessionState state, Exception exception) {// Invoke user-callback.onSessionCallback(callbackSession, state, exception, listener);}};Session.OpenRequest openRequest = new Session.OpenRequest(activity).setCallback(callback).setLoginBehavior(behavior).setRequestCode(activityCode).setPermissions(Arrays.asList(pendingAuthorizationPermissions));openSession(pendingOpeningSession, openRequest, pendingAuthorizationPermissions.length > 0);}private void openSession(Session session, Session.OpenRequest openRequest, boolean isPublish) {openRequest.setIsLegacy(true);if (isPublish) {session.openForPublish(openRequest);} else {session.openForRead(openRequest);}}@SuppressWarnings("deprecation")private void onSessionCallback(Session callbackSession, SessionState state, Exception exception,DialogListener listener) {Bundle extras = callbackSession.getAuthorizationBundle();if (state == SessionState.OPENED) {Session sessionToClose = null;synchronized (Facebook.this.lock) {if (callbackSession != Facebook.this.session) {sessionToClose = Facebook.this.session;Facebook.this.session = callbackSession;Facebook.this.sessionInvalidated = false;}}if (sessionToClose != null) {sessionToClose.close();}listener.onComplete(extras);} else if (exception != null) {if (exception instanceof FacebookOperationCanceledException) {listener.onCancel();} else if ((exception instanceof FacebookAuthorizationException) && (extras != null)&& extras.containsKey(Session.WEB_VIEW_ERROR_CODE_KEY)&& extras.containsKey(Session.WEB_VIEW_FAILING_URL_KEY)) {DialogError error = new DialogError(exception.getMessage(),extras.getInt(Session.WEB_VIEW_ERROR_CODE_KEY),extras.getString(Session.WEB_VIEW_FAILING_URL_KEY));listener.onError(error);} else {FacebookError error = new FacebookError(exception.getMessage());listener.onFacebookError(error);}}}/*** Helper to validate a service intent by resolving and checking the* provider's package signature.** @param context* @param intent* @return true if the service intent resolution happens successfully and* the signatures match.*/private boolean validateServiceIntent(Context context, Intent intent) {ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, 0);if (resolveInfo == null) {return false;}return validateAppSignatureForPackage(context, resolveInfo.serviceInfo.packageName);}/*** Query the signature for the application that would be invoked by the* given intent and verify that it matches the FB application's signature.** @param context* @param packageName* @return true if the app's signature matches the expected signature.*/private boolean validateAppSignatureForPackage(Context context, String packageName) {PackageInfo packageInfo;try {packageInfo = context.getPackageManager().getPackageInfo(packageName, PackageManager.GET_SIGNATURES);} catch (NameNotFoundException e) {return false;}for (Signature signature : packageInfo.signatures) {if (signature.toCharsString().equals(FB_APP_SIGNATURE)) {return true;}}return false;}/*** IMPORTANT: If you are using the deprecated authorize() method,* this method must be invoked at the top of the calling* activity's onActivityResult() function or Facebook authentication will* not function properly!* <p/>* If your calling activity does not currently implement onActivityResult(),* you must implement it and include a call to this method if you intend to* use the authorize() method in this SDK.* <p/>* For more information, see* http://developer.android.com/reference/android/app/* Activity.html#onActivityResult(int, int, android.content.Intent)* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.*/@Deprecatedpublic void authorizeCallback(int requestCode, int resultCode, Intent data) {checkUserSession("authorizeCallback");Session pending = this.pendingOpeningSession;if (pending != null) {if (pending.onActivityResult(this.pendingAuthorizationActivity, requestCode, resultCode, data)) {this.pendingOpeningSession = null;this.pendingAuthorizationActivity = null;this.pendingAuthorizationPermissions = null;}}}/*** Refresh OAuth access token method. Binds to Facebook for Android* stand-alone application application to refresh the access token. This* method tries to connect to the Facebook App which will handle the* authentication flow, and return a new OAuth access token. This method* will automatically replace the old token with a new one. Note that this* method is asynchronous and the callback will be invoked in the original* calling thread (not in a background thread).* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param context* The Android Context that will be used to bind to the Facebook* RefreshToken Service* @param serviceListener* Callback interface for notifying the calling application when* the refresh request has completed or failed (can be null). In* case of a success a new token can be found inside the result* Bundle under Facebook.ACCESS_TOKEN key.* @return true if the binding to the RefreshToken Service was created*/@Deprecatedpublic boolean extendAccessToken(Context context, ServiceListener serviceListener) {checkUserSession("extendAccessToken");Intent intent = new Intent();intent.setClassName("com.facebook.katana", "com.facebook.katana.platform.TokenRefreshService");// Verify that the application whose package name is// com.facebook.katana// has the expected FB app signature.if (!validateServiceIntent(context, intent)) {return false;}return context.bindService(intent, new TokenRefreshServiceConnection(context, serviceListener),Context.BIND_AUTO_CREATE);}/*** Calls extendAccessToken if shouldExtendAccessToken returns true.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @return the same value as extendAccessToken if the the token requires* refreshing, true otherwise*/@Deprecatedpublic boolean extendAccessTokenIfNeeded(Context context, ServiceListener serviceListener) {checkUserSession("extendAccessTokenIfNeeded");if (shouldExtendAccessToken()) {return extendAccessToken(context, serviceListener);}return true;}/*** Check if the access token requires refreshing.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @return true if the last time a new token was obtained was over 24 hours* ago.*/@Deprecatedpublic boolean shouldExtendAccessToken() {checkUserSession("shouldExtendAccessToken");return isSessionValid()&& (System.currentTimeMillis() - lastAccessUpdateMillisecondsAfterEpoch >= REFRESH_TOKEN_BARRIER);}/*** Handles connection to the token refresh service (this service is a part* of Facebook App).*/private class TokenRefreshServiceConnection implements ServiceConnection {final Messenger messageReceiver = new Messenger(new TokenRefreshConnectionHandler(Facebook.this, this));final ServiceListener serviceListener;final Context applicationsContext;Messenger messageSender = null;public TokenRefreshServiceConnection(Context applicationsContext, ServiceListener serviceListener) {this.applicationsContext = applicationsContext;this.serviceListener = serviceListener;}@Overridepublic void onServiceConnected(ComponentName className, IBinder service) {messageSender = new Messenger(service);refreshToken();}@Overridepublic void onServiceDisconnected(ComponentName arg) {serviceListener.onError(new Error("Service disconnected"));try {// We returned an error so there's no point in// keeping the binding open.applicationsContext.unbindService(TokenRefreshServiceConnection.this);} catch (IllegalArgumentException ex) {// Do nothing, the connection was already unbound}}private void refreshToken() {Bundle requestData = new Bundle();requestData.putString(TOKEN, accessToken);Message request = Message.obtain();request.setData(requestData);request.replyTo = messageReceiver;try {messageSender.send(request);} catch (RemoteException e) {serviceListener.onError(new Error("Service connection error"));}}}// Creating a static Handler class to reduce the possibility of a memory leak.// Handler objects for the same thread all share a common Looper object, which they post messages// to and read from. As messages contain target Handler, as long as there are messages with target// handler in the message queue, the handler cannot be garbage collected. If handler is not static,// the instance of the containing class also cannot be garbage collected even if it is destroyed.private static class TokenRefreshConnectionHandler extends Handler {WeakReference<Facebook> facebookWeakReference;WeakReference<TokenRefreshServiceConnection> connectionWeakReference;TokenRefreshConnectionHandler(Facebook facebook, TokenRefreshServiceConnection connection) {super();facebookWeakReference = new WeakReference<Facebook>(facebook);connectionWeakReference = new WeakReference<TokenRefreshServiceConnection>(connection);}@Override@SuppressWarnings("deprecation")public void handleMessage(Message msg) {Facebook facebook = facebookWeakReference.get();TokenRefreshServiceConnection connection = connectionWeakReference.get();if (facebook == null || connection == null) {return;}String token = msg.getData().getString(TOKEN);// Legacy functions in Facebook class (and ServiceListener implementors) expect expires_in in// milliseconds from epochlong expiresAtMsecFromEpoch = msg.getData().getLong(EXPIRES) * 1000L;if (token != null) {facebook.setAccessToken(token);facebook.setAccessExpires(expiresAtMsecFromEpoch);Session refreshSession = facebook.session;if (refreshSession != null) {// Session.internalRefreshToken expects the original bundle with expires_in in seconds from// epoch.LegacyHelper.extendTokenCompleted(refreshSession, msg.getData());}if (connection.serviceListener != null) {// To avoid confusion we should return the expiration time in// the same format as the getAccessExpires() function - that// is in milliseconds.Bundle resultBundle = (Bundle) msg.getData().clone();resultBundle.putLong(EXPIRES, expiresAtMsecFromEpoch);connection.serviceListener.onComplete(resultBundle);}} else if (connection.serviceListener != null) { // extract errors only if// client wants themString error = msg.getData().getString("error");if (msg.getData().containsKey("error_code")) {int errorCode = msg.getData().getInt("error_code");connection.serviceListener.onFacebookError(new FacebookError(error, null, errorCode));} else {connection.serviceListener.onError(new Error(error != null ? error : "Unknown service error"));}}// The refreshToken function should be called rarely,// so there is no point in keeping the binding open.connection.applicationsContext.unbindService(connection);}}/*** Invalidate the current user session by removing the access token in* memory, clearing the browser cookie, and calling auth.expireSession* through the API.* <p/>* Note that this method blocks waiting for a network response, so do not* call it in a UI thread.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param context* The Android context in which the logout should be called: it* should be the same context in which the login occurred in* order to clear any stored cookies* @throws IOException* @throws MalformedURLException* @return JSON string representation of the auth.expireSession response* ("true" if successful)*/@Deprecatedpublic String logout(Context context) throws MalformedURLException, IOException {return logoutImpl(context);}String logoutImpl(Context context) throws MalformedURLException, IOException {checkUserSession("logout");Bundle b = new Bundle();b.putString("method", "auth.expireSession");String response = request(b);long currentTimeMillis = System.currentTimeMillis();Session sessionToClose = null;synchronized (this.lock) {sessionToClose = session;session = null;accessToken = null;accessExpiresMillisecondsAfterEpoch = 0;lastAccessUpdateMillisecondsAfterEpoch = currentTimeMillis;sessionInvalidated = false;}if (sessionToClose != null) {sessionToClose.closeAndClearTokenInformation();}return response;}/*** Make a request 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.* <p/>* See http://developers.facebook.com/docs/reference/rest/* <p/>* Note that this method blocks waiting for a network response, so do not* call it in a UI thread.* <p/>* Example: <code>* Bundle parameters = new Bundle();* parameters.putString("method", "auth.expireSession");* String response = request(parameters);* </code>* <p/>* This method is deprecated. See {@link Facebook} and {@link Request} for more info.** @param parameters* Key-value pairs of parameters to the request. Refer to the* documentation: one of the parameters must be "method".* @throws IOException* if a network error occurs* @throws MalformedURLException* if accessing an invalid endpoint* @throws IllegalArgumentException* if one of the parameters is not "method"* @return JSON string representation of the response*/@Deprecatedpublic String request(Bundle parameters) throws MalformedURLException, IOException {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 requestImpl(null, parameters, "GET");}/*** Make a request to the Facebook Graph API without any parameters.* <p/>* See http://developers.facebook.com/docs/api* <p/>* Note that this method blocks waiting for a network response, so do not* call it in a UI thread.* <p/>* This method is deprecated. See {@link Facebook} and {@link Request} for more info.** @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 IOException* @throws MalformedURLException* @return JSON string representation of the response*/@Deprecatedpublic String request(String graphPath) throws MalformedURLException, IOException {return requestImpl(graphPath, new Bundle(), "GET");}/*** Make a request to the Facebook Graph API with the given string parameters* using an HTTP GET (default method).* <p/>* See http://developers.facebook.com/docs/api* <p/>* Note that this method blocks waiting for a network response, so do not* call it in a UI thread.* <p/>* This method is deprecated. See {@link Facebook} and {@link Request} for more info.** @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 IOException* @throws MalformedURLException* @return JSON string representation of the response*/@Deprecatedpublic String request(String graphPath, Bundle parameters) throws MalformedURLException, IOException {return requestImpl(graphPath, parameters, "GET");}/*** Synchronously make a request to the Facebook Graph API with the given* HTTP method and string parameters. Note that binary data parameters (e.g.* pictures) are not yet supported by this helper function.* <p/>* See http://developers.facebook.com/docs/api* <p/>* Note that this method blocks waiting for a network response, so do not* call it in a UI thread.* <p/>* This method is deprecated. See {@link Facebook} and {@link Request} for more info.** @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 params* 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 IOException* @throws MalformedURLException* @return JSON string representation of the response*/@Deprecatedpublic String request(String graphPath, Bundle params, String httpMethod) throws FileNotFoundException,MalformedURLException, IOException {return requestImpl(graphPath, params, httpMethod);}// Internal call to avoid deprecated warnings.@SuppressWarnings("deprecation")String requestImpl(String graphPath, Bundle params, String httpMethod) throws FileNotFoundException,MalformedURLException, IOException {params.putString("format", "json");if (isSessionValid()) {params.putString(TOKEN, getAccessToken());}String url = (graphPath != null) ? GRAPH_BASE_URL + graphPath : RESTSERVER_URL;return Util.openUrl(url, httpMethod, params);}/*** Generate a UI dialog for the request action in the given Android context.* <p/>* Note that this method is asynchronous and the callback will be invoked in* the original calling thread (not in a background thread).** This method is deprecated. See {@link com.facebook.widget.WebDialog}.** @param context* The Android context in which we will generate this dialog.* @param action* String representation of the desired method: e.g. "login",* "stream.publish", ...* @param listener* Callback interface to notify the application when the dialog* has completed.*/@Deprecatedpublic void dialog(Context context, String action, DialogListener listener) {dialog(context, action, new Bundle(), listener);}/*** Generate a UI dialog for the request action in the given Android context* with the provided parameters.* <p/>* Note that this method is asynchronous and the callback will be invoked in* the original calling thread (not in a background thread).** This method is deprecated. See {@link com.facebook.widget.WebDialog}.** @param context* The Android context in which we will generate this dialog.* @param action* String representation of the desired method: e.g. "feed" ...* @param parameters* String key-value pairs to be passed as URL parameters.* @param listener* Callback interface to notify the application when the dialog* has completed.*/@Deprecatedpublic void dialog(Context context, String action, Bundle parameters, final DialogListener listener) {parameters.putString("display", "touch");parameters.putString("redirect_uri", REDIRECT_URI);if (action.equals(LOGIN)) {parameters.putString("type", "user_agent");parameters.putString("client_id", mAppId);} else {parameters.putString("app_id", mAppId);// We do not want to add an access token when displaying the auth dialog.if (isSessionValid()) {parameters.putString(TOKEN, getAccessToken());}}if (context.checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {Util.showAlert(context, "Error", "Application requires permission to access the Internet");} else {new FbDialog(context, action, parameters, listener).show();}}/*** Returns whether the current access token is valid** @return boolean - whether this object has an non-expired session token*/@Deprecatedpublic boolean isSessionValid() {return (getAccessToken() != null)&& ((getAccessExpires() == 0) || (System.currentTimeMillis() < getAccessExpires()));}/*** Allows the user to set a Session for the Facebook class to use.* If a Session is set here, then one should not use the authorize, logout,* or extendAccessToken methods which alter the Session object since that may* result in undefined behavior. Using those methods after setting the* session here will result in exceptions being thrown.** @param session the Session object to use, cannot be null*/@Deprecatedpublic void setSession(Session session) {if (session == null) {throw new IllegalArgumentException("session cannot be null");}synchronized (this.lock) {this.userSetSession = session;}}private void checkUserSession(String methodName) {if (userSetSession != null) {throw new UnsupportedOperationException(String.format("Cannot call %s after setSession has been called.", methodName));}}/*** Get the underlying Session object to use with 3.0 api.** @return Session - underlying session*/@Deprecatedpublic final Session getSession() {while (true) {String cachedToken = null;Session oldSession = null;synchronized (this.lock) {if (userSetSession != null) {return userSetSession;}if ((session != null) || !sessionInvalidated) {return session;}cachedToken = accessToken;oldSession = session;}if (cachedToken == null) {return null;}// At this point we do not have a valid session, but mAccessToken is// non-null.// So we can try building a session based on that.List<String> permissions;if (oldSession != null) {permissions = oldSession.getPermissions();} else if (pendingAuthorizationPermissions != null) {permissions = Arrays.asList(pendingAuthorizationPermissions);} else {permissions = Collections.<String>emptyList();}Session newSession = new Session.Builder(pendingAuthorizationActivity).setApplicationId(mAppId).setTokenCachingStrategy(getTokenCache()).build();if (newSession.getState() != SessionState.CREATED_TOKEN_LOADED) {return null;}Session.OpenRequest openRequest =new Session.OpenRequest(pendingAuthorizationActivity).setPermissions(permissions);openSession(newSession, openRequest, !permissions.isEmpty());Session invalidatedSession = null;Session returnSession = null;synchronized (this.lock) {if (sessionInvalidated || (session == null)) {invalidatedSession = session;returnSession = session = newSession;sessionInvalidated = false;}}if (invalidatedSession != null) {invalidatedSession.close();}if (returnSession != null) {return returnSession;}// Else token state changed between the synchronized blocks, so// retry..}}/*** Retrieve the OAuth 2.0 access token for API access: treat with care.* Returns null if no session exists.** @return String - access token*/@Deprecatedpublic String getAccessToken() {Session s = getSession();if (s != null) {return s.getAccessToken();} else {return null;}}/*** Retrieve the current session's expiration time (in milliseconds since* Unix epoch), or 0 if the session doesn't expire or doesn't exist.** @return long - session expiration time*/@Deprecatedpublic long getAccessExpires() {Session s = getSession();if (s != null) {return s.getExpirationDate().getTime();} else {return accessExpiresMillisecondsAfterEpoch;}}/*** Retrieve the last time the token was updated (in milliseconds since* the Unix epoch), or 0 if the token has not been set.** @return long - timestamp of the last token update.*/@Deprecatedpublic long getLastAccessUpdate() {return lastAccessUpdateMillisecondsAfterEpoch;}/*** Restore the token, expiration time, and last update time from cached values.* These should be values obtained from getAccessToken(), getAccessExpires, and* getLastAccessUpdate() respectively.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param accessToken - access token* @param accessExpires - access token expiration time* @param lastAccessUpdate - timestamp of the last token update*/@Deprecatedpublic void setTokenFromCache(String accessToken, long accessExpires, long lastAccessUpdate) {checkUserSession("setTokenFromCache");synchronized (this.lock) {this.accessToken = accessToken;accessExpiresMillisecondsAfterEpoch = accessExpires;lastAccessUpdateMillisecondsAfterEpoch = lastAccessUpdate;}}/*** Set the OAuth 2.0 access token for API access.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param token* - access token*/@Deprecatedpublic void setAccessToken(String token) {checkUserSession("setAccessToken");synchronized (this.lock) {accessToken = token;lastAccessUpdateMillisecondsAfterEpoch = System.currentTimeMillis();sessionInvalidated = true;}}/*** Set the current session's expiration time (in milliseconds since Unix* epoch), or 0 if the session doesn't expire.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param timestampInMsec* - timestamp in milliseconds*/@Deprecatedpublic void setAccessExpires(long timestampInMsec) {checkUserSession("setAccessExpires");synchronized (this.lock) {accessExpiresMillisecondsAfterEpoch = timestampInMsec;lastAccessUpdateMillisecondsAfterEpoch = System.currentTimeMillis();sessionInvalidated = true;}}/*** Set the current session's duration (in seconds since Unix epoch), or "0"* if session doesn't expire.* <p/>* This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param expiresInSecsFromNow* - duration in seconds (or 0 if the session doesn't expire)*/@Deprecatedpublic void setAccessExpiresIn(String expiresInSecsFromNow) {checkUserSession("setAccessExpiresIn");if (expiresInSecsFromNow != null) {long expires = expiresInSecsFromNow.equals("0") ? 0 : System.currentTimeMillis()+ Long.parseLong(expiresInSecsFromNow) * 1000L;setAccessExpires(expires);}}/*** This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @return the String representing application ID*/@Deprecatedpublic String getAppId() {return mAppId;}/*** This method is deprecated. See {@link Facebook} and {@link Session} for more info.** @param appId the String representing the application ID*/@Deprecatedpublic void setAppId(String appId) {checkUserSession("setAppId");synchronized (this.lock) {mAppId = appId;sessionInvalidated = true;}}private TokenCachingStrategy getTokenCache() {// Intentionally not volatile/synchronized--it is okay if we race to// create more than one of these.if (tokenCache == null) {tokenCache = new SetterTokenCachingStrategy();}return tokenCache;}private static String[] stringArray(List<String> list) {int size = (list != null) ? list.size() : 0;String[] array = new String[size];if (list != null) {for (int i = 0; i < array.length; i++) {array[i] = list.get(i);}}return array;}private static List<String> stringList(String[] array) {if (array != null) {return Arrays.asList(array);} else {return Collections.emptyList();}}private class SetterTokenCachingStrategy extends TokenCachingStrategy {@Overridepublic Bundle load() {Bundle bundle = new Bundle();if (accessToken != null) {TokenCachingStrategy.putToken(bundle, accessToken);TokenCachingStrategy.putExpirationMilliseconds(bundle, accessExpiresMillisecondsAfterEpoch);TokenCachingStrategy.putPermissions(bundle, stringList(pendingAuthorizationPermissions));TokenCachingStrategy.putSource(bundle, AccessTokenSource.WEB_VIEW);TokenCachingStrategy.putLastRefreshMilliseconds(bundle, lastAccessUpdateMillisecondsAfterEpoch);}return bundle;}@Overridepublic void save(Bundle bundle) {accessToken = TokenCachingStrategy.getToken(bundle);accessExpiresMillisecondsAfterEpoch = TokenCachingStrategy.getExpirationMilliseconds(bundle);pendingAuthorizationPermissions = stringArray(TokenCachingStrategy.getPermissions(bundle));lastAccessUpdateMillisecondsAfterEpoch = TokenCachingStrategy.getLastRefreshMilliseconds(bundle);}@Overridepublic void clear() {accessToken = null;}}/*** Get Attribution ID for app install conversion tracking.* <p/>* This method is deprecated. See {@link Facebook} and {@link Settings} for more info.** @param contentResolver* @return Attribution ID that will be used for conversion tracking. It will be null only if* the user has not installed or logged in to the Facebook app.*/@Deprecatedpublic static String getAttributionId(ContentResolver contentResolver) {return Settings.getAttributionId(contentResolver);}/*** Get the auto install publish setting. If true, an install event will be published during authorize(), unless* it has occurred previously or the app does not have install attribution enabled on the application's developer* config page.* <p/>* This method is deprecated. See {@link Facebook} and {@link Settings} for more info.** @return a Boolean indicating whether installation of the app should be auto-published.*/@Deprecatedpublic boolean getShouldAutoPublishInstall() {return Settings.getShouldAutoPublishInstall();}/*** Sets whether auto publishing of installs will occur.* <p/>* This method is deprecated. See {@link Facebook} and {@link Settings} for more info.** @param value a Boolean indicating whether installation of the app should be auto-published.*/@Deprecatedpublic void setShouldAutoPublishInstall(boolean value) {Settings.setShouldAutoPublishInstall(value);}/*** Callback interface for dialog requests.* <p/>* THIS CLASS SHOULD BE CONSIDERED DEPRECATED.* <p/>* All public members of this class are intentionally deprecated.* New code should instead use* {@link com.facebook.widget.WebDialog}* <p/>* Adding @Deprecated to this class causes warnings in other deprecated classes* that reference this one. That is the only reason this entire class is not* deprecated.** @devDocDeprecated*/public static interface DialogListener {/*** Called when a dialog completes.** Executed by the thread that initiated the dialog.** @param values* Key-value string pairs extracted from the response.*/public void onComplete(Bundle values);/*** Called when a Facebook responds to a dialog with an error.** Executed by the thread that initiated the dialog.**/public void onFacebookError(FacebookError e);/*** Called when a dialog has an error.** Executed by the thread that initiated the dialog.**/public void onError(DialogError e);/*** Called when a dialog is canceled by the user.** Executed by the thread that initiated the dialog.**/public void onCancel();}/*** Callback interface for service requests.* <p/>* THIS CLASS SHOULD BE CONSIDERED DEPRECATED.* <p/>* All public members of this class are intentionally deprecated.* New code should instead use* {@link Session} to manage session state.* <p/>* Adding @Deprecated to this class causes warnings in other deprecated classes* that reference this one. That is the only reason this entire class is not* deprecated.** @devDocDeprecated*/public static interface ServiceListener {/*** Called when a service request completes.** @param values* Key-value string pairs extracted from the response.*/public void onComplete(Bundle values);/*** Called when a Facebook server responds to the request with an error.*/public void onFacebookError(FacebookError e);/*** Called when a Facebook Service responds to the request with an error.*/public void onError(Error e);}@Deprecatedpublic static final String FB_APP_SIGNATURE ="30820268308201d102044a9c4610300d06092a864886f70d0101040500307a310"+ "b3009060355040613025553310b30090603550408130243413112301006035504"+ "07130950616c6f20416c746f31183016060355040a130f46616365626f6f6b204"+ "d6f62696c653111300f060355040b130846616365626f6f6b311d301b06035504"+ "03131446616365626f6f6b20436f72706f726174696f6e3020170d30393038333"+ "13231353231365a180f32303530303932353231353231365a307a310b30090603"+ "55040613025553310b30090603550408130243413112301006035504071309506"+ "16c6f20416c746f31183016060355040a130f46616365626f6f6b204d6f62696c"+ "653111300f060355040b130846616365626f6f6b311d301b06035504031314466"+ "16365626f6f6b20436f72706f726174696f6e30819f300d06092a864886f70d01"+ "0101050003818d0030818902818100c207d51df8eb8c97d93ba0c8c1002c928fa"+ "b00dc1b42fca5e66e99cc3023ed2d214d822bc59e8e35ddcf5f44c7ae8ade50d7"+ "e0c434f500e6c131f4a2834f987fc46406115de2018ebbb0d5a3c261bd97581cc"+ "fef76afc7135a6d59e8855ecd7eacc8f8737e794c60a761c536b72b11fac8e603"+ "f5da1a2d54aa103b8a13c0dbc10203010001300d06092a864886f70d010104050"+ "0038181005ee9be8bcbb250648d3b741290a82a1c9dc2e76a0af2f2228f1d9f9c"+ "4007529c446a70175c5a900d5141812866db46be6559e2141616483998211f4a6"+ "73149fb2232a10d247663b26a9031e15f84bc1c74d141ff98a02d76f85b2c8ab2"+ "571b6469b232d8e768a7f7ca04f7abe4a775615916c07940656b58717457b42bd"+ "928a2";}