Facebook.Unity/Mobile/Android/AndroidFacebook.cs (777 lines of code) (raw):

/** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, * copy, modify, and distribute this software in source code or binary form for use * in connection with the web services and APIs provided by Facebook. * * As with any software that integrates with the Facebook platform, your use of * this software is subject to the Facebook Developer Principles and Policies * [http://developers.facebook.com/policy/]. This copyright notice shall be * included in all copies or substantial portions of the software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ namespace Facebook.Unity.Mobile.Android { using System; using System.Collections.Generic; using System.Linq; using System.Globalization; using System.Reflection; using UnityEngine; internal sealed class AndroidFacebook : MobileFacebook { public const string LoginPermissionsKey = "scope"; // This class holds all the of the wrapper methods that we call into private bool limitEventUsage; private IAndroidWrapper androidWrapper; private string userID; public AndroidFacebook() : this(GetAndroidWrapper(), new CallbackManager()) { } public AndroidFacebook(IAndroidWrapper androidWrapper, CallbackManager callbackManager) : base(callbackManager) { this.KeyHash = string.Empty; this.androidWrapper = androidWrapper; } // key Hash used for Android SDK public string KeyHash { get; private set; } public override bool LimitEventUsage { get { return this.limitEventUsage; } set { this.limitEventUsage = value; this.CallFB("SetLimitEventUsage", value.ToString()); } } public override string UserID { get { return userID; } set { this.userID = value; this.CallFB("SetUserID", value); } } public override void SetDataProcessingOptions(IEnumerable<string> options, int country, int state) { var args = new MethodArguments(); args.AddList<string>("options", options); args.AddPrimative<int>("country", country); args.AddPrimative<int>("state", state); this.CallFB("SetDataProcessingOptions", args.ToJsonString()); } public override void SetAutoLogAppEventsEnabled(bool autoLogAppEventsEnabled) { this.CallFB("SetAutoLogAppEventsEnabled", autoLogAppEventsEnabled.ToString()); } public override void SetAdvertiserIDCollectionEnabled(bool advertiserIDCollectionEnabled) { this.CallFB("SetAdvertiserIDCollectionEnabled", advertiserIDCollectionEnabled.ToString()); } public override bool SetAdvertiserTrackingEnabled(bool advertiserTrackingEnabled) { return false; } public override void SetPushNotificationsDeviceTokenString(string token) { this.CallFB("SetPushNotificationsDeviceTokenString", token); } public override string SDKName { get { return "FBAndroidSDK"; } } public override string SDKVersion { get { return this.androidWrapper.CallStatic<string>("GetSdkVersion"); } } public void Init( string appId, HideUnityDelegate hideUnityDelegate, InitDelegate onInitComplete) { // Set the user agent suffix for graph requests // This should be set before a call to init to ensure that // requests made during init include this suffix. this.CallFB( "SetUserAgentSuffix", string.Format(Constants.UnitySDKUserAgentSuffixLegacy)); base.Init(onInitComplete); var args = new MethodArguments(); args.AddString("appId", appId); var initCall = new JavaMethodCall<IResult>(this, "Init"); initCall.Call(args); this.userID = this.androidWrapper.CallStatic<string>("GetUserID"); } public override void EnableProfileUpdatesOnAccessTokenChange(bool enable) { if (Debug.isDebugBuild) { Debug.Log("This function is only implemented on iOS."); } return; } public override void LoginWithTrackingPreference( string tracking, IEnumerable<string> permissions, string nonce, FacebookDelegate<ILoginResult> callback) { if (Debug.isDebugBuild) { Debug.Log("This function is only implemented on iOS. Please use .LoginWithReadPermissions() or .LoginWithPublishPermissions() on other platforms."); } return; } public override void LogInWithReadPermissions( IEnumerable<string> permissions, FacebookDelegate<ILoginResult> callback) { MethodArguments args = new MethodArguments(); args.AddCommaSeparatedList(AndroidFacebook.LoginPermissionsKey, permissions); var loginCall = new JavaMethodCall<ILoginResult>(this, "LoginWithReadPermissions"); loginCall.Callback = callback; loginCall.Call(args); } public override void LogInWithPublishPermissions( IEnumerable<string> permissions, FacebookDelegate<ILoginResult> callback) { MethodArguments args = new MethodArguments(); args.AddCommaSeparatedList(AndroidFacebook.LoginPermissionsKey, permissions); var loginCall = new JavaMethodCall<ILoginResult>(this, "LoginWithPublishPermissions"); loginCall.Callback = callback; loginCall.Call(args); } public override void LogOut() { base.LogOut(); var logoutCall = new JavaMethodCall<IResult>(this, "Logout"); logoutCall.Call(); } public override AuthenticationToken CurrentAuthenticationToken() { String authTokenString = this.androidWrapper.CallStatic<string>("GetCurrentAuthenticationToken"); if (!String.IsNullOrEmpty(authTokenString)) { IDictionary<string, string> token = Utilities.ParseStringDictionaryFromString(authTokenString); string tokenString; string nonce; token.TryGetValue("auth_token_string", out tokenString); token.TryGetValue("auth_nonce", out nonce); try { return new AuthenticationToken(tokenString, nonce); } catch (Exception) { Debug.Log("An unexpected error occurred while retrieving the current authentication token"); } } return null; } public override Profile CurrentProfile() { String profileString = this.androidWrapper.CallStatic<string>("GetCurrentProfile"); if (!String.IsNullOrEmpty(profileString)) { try { IDictionary<string, string> profile = Utilities.ParseStringDictionaryFromString(profileString); string id; string firstName; string middleName; string lastName; string name; string email; string imageURL; string linkURL; string friendIDs; string birthday; string gender; profile.TryGetValue("userID", out id); profile.TryGetValue("firstName", out firstName); profile.TryGetValue("middleName", out middleName); profile.TryGetValue("lastName", out lastName); profile.TryGetValue("name", out name); profile.TryGetValue("email", out email); profile.TryGetValue("imageURL", out imageURL); profile.TryGetValue("linkURL", out linkURL); profile.TryGetValue("friendIDs", out friendIDs); profile.TryGetValue("birthday", out birthday); profile.TryGetValue("gender", out gender); UserAgeRange ageRange = UserAgeRange.AgeRangeFromDictionary(profile); FBLocation hometown = FBLocation.FromDictionary("hometown", profile); FBLocation location = FBLocation.FromDictionary("location", profile); return new Profile( userID, firstName, middleName, lastName, name, email, imageURL, linkURL, friendIDs?.Split(','), birthday, ageRange, hometown, location, gender); } catch (Exception) { return null; } } return null; } public void RetrieveLoginStatus(FacebookDelegate<ILoginStatusResult> callback) { var loginCall = new JavaMethodCall<ILoginStatusResult>(this, "RetrieveLoginStatus"); loginCall.Callback = callback; loginCall.Call(); } public void OnLoginStatusRetrieved(ResultContainer resultContainer) { var result = new LoginStatusResult(resultContainer); this.OnAuthResponse(result); } public override void AppRequest( string message, OGActionType? actionType, string objectId, IEnumerable<string> to, IEnumerable<object> filters, IEnumerable<string> excludeIds, int? maxRecipients, string data, string title, FacebookDelegate<IAppRequestResult> callback) { this.ValidateAppRequestArgs( message, actionType, objectId, to, filters, excludeIds, maxRecipients, data, title, callback); MethodArguments args = new MethodArguments(); args.AddString("message", message); args.AddNullablePrimitive("action_type", actionType); args.AddString("object_id", objectId); args.AddCommaSeparatedList("to", to); if (filters != null && filters.Any()) { string mobileFilter = filters.First() as string; if (mobileFilter != null) { args.AddString("filters", mobileFilter); } } args.AddNullablePrimitive("max_recipients", maxRecipients); args.AddString("data", data); args.AddString("title", title); var appRequestCall = new JavaMethodCall<IAppRequestResult>(this, "AppRequest"); appRequestCall.Callback = callback; appRequestCall.Call(args); } public override void ShareLink( Uri contentURL, string contentTitle, string contentDescription, Uri photoURL, FacebookDelegate<IShareResult> callback) { MethodArguments args = new MethodArguments(); args.AddUri("content_url", contentURL); args.AddString("content_title", contentTitle); args.AddString("content_description", contentDescription); args.AddUri("photo_url", photoURL); var shareLinkCall = new JavaMethodCall<IShareResult>(this, "ShareLink"); shareLinkCall.Callback = callback; shareLinkCall.Call(args); } public override void FeedShare( string toId, Uri link, string linkName, string linkCaption, string linkDescription, Uri picture, string mediaSource, FacebookDelegate<IShareResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("toId", toId); args.AddUri("link", link); args.AddString("linkName", linkName); args.AddString("linkCaption", linkCaption); args.AddString("linkDescription", linkDescription); args.AddUri("picture", picture); args.AddString("mediaSource", mediaSource); var call = new JavaMethodCall<IShareResult>(this, "FeedShare"); call.Callback = callback; call.Call(args); } public override void GetAppLink( FacebookDelegate<IAppLinkResult> callback) { var getAppLink = new JavaMethodCall<IAppLinkResult>(this, "GetAppLink"); getAppLink.Callback = callback; getAppLink.Call(); } public void ClearAppLink() { this.CallFB("ClearAppLink", null); } public override void AppEventsLogEvent( string logEvent, float? valueToSum, Dictionary<string, object> parameters) { MethodArguments args = new MethodArguments(); args.AddString("logEvent", logEvent); args.AddString("valueToSum", valueToSum?.ToString(CultureInfo.InvariantCulture)); args.AddDictionary("parameters", parameters); var appEventcall = new JavaMethodCall<IResult>(this, "LogAppEvent"); appEventcall.Call(args); } public override void AppEventsLogPurchase( float logPurchase, string currency, Dictionary<string, object> parameters) { MethodArguments args = new MethodArguments(); args.AddString("logPurchase", logPurchase.ToString(CultureInfo.InvariantCulture)); args.AddString("currency", currency); args.AddDictionary("parameters", parameters); var logPurchaseCall = new JavaMethodCall<IResult>(this, "LogAppEvent"); logPurchaseCall.Call(args); } public override bool IsImplicitPurchaseLoggingEnabled() { return this.androidWrapper.CallStatic<bool>("IsImplicitPurchaseLoggingEnabled"); } public override void ActivateApp(string appId) { this.CallFB("ActivateApp", null); } public override void FetchDeferredAppLink( FacebookDelegate<IAppLinkResult> callback) { MethodArguments args = new MethodArguments(); var fetchDeferredAppLinkData = new JavaMethodCall<IAppLinkResult>(this, "FetchDeferredAppLinkData"); fetchDeferredAppLinkData.Callback = callback; fetchDeferredAppLinkData.Call(args); } public override void RefreshCurrentAccessToken( FacebookDelegate<IAccessTokenRefreshResult> callback) { var refreshCurrentAccessToken = new JavaMethodCall<IAccessTokenRefreshResult>( this, "RefreshCurrentAccessToken"); refreshCurrentAccessToken.Callback = callback; refreshCurrentAccessToken.Call(); } public override void OpenFriendFinderDialog( FacebookDelegate<IGamingServicesFriendFinderResult> callback) { var openFriendFinderDialog = new JavaMethodCall<IGamingServicesFriendFinderResult>( this, "OpenFriendFinderDialog") { Callback = callback }; openFriendFinderDialog.Call(); } public override void GetFriendFinderInvitations(FacebookDelegate<IFriendFinderInvitationResult> callback) { throw new NotImplementedException(); } public override void DeleteFriendFinderInvitation(string invitationId, FacebookDelegate<IFriendFinderInvitationResult> callback) { throw new NotImplementedException(); } public override void UploadImageToMediaLibrary( string caption, Uri imageUri, bool shouldLaunchMediaDialog, FacebookDelegate<IMediaUploadResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("caption", caption); args.AddUri("imageUri", imageUri); args.AddString("shouldLaunchMediaDialog", shouldLaunchMediaDialog.ToString()); var uploadImageToMediaLibrary = new JavaMethodCall<IMediaUploadResult>( this, "UploadImageToMediaLibrary") { Callback = callback }; uploadImageToMediaLibrary.Call(args); } public override void UploadVideoToMediaLibrary( string caption, Uri videoUri, bool shouldLaunchMediaDialog, FacebookDelegate<IMediaUploadResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("caption", caption); args.AddUri("videoUri", videoUri); var uploadImageToMediaLibrary = new JavaMethodCall<IMediaUploadResult>( this, "UploadVideoToMediaLibrary") { Callback = callback }; uploadImageToMediaLibrary.Call(args); } public override void OnIAPReady( FacebookDelegate<IIAPReadyResult> callback) { var onIAPReady = new JavaMethodCall<IIAPReadyResult>( this, "OnIAPReady") { Callback = callback }; onIAPReady.Call(); } public override void GetCatalog( FacebookDelegate<ICatalogResult> callback) { var getCatalog = new JavaMethodCall<ICatalogResult>( this, "GetCatalog") { Callback = callback }; getCatalog.Call(); } public override void GetPurchases( FacebookDelegate<IPurchasesResult> callback) { var getPurchases = new JavaMethodCall<IPurchasesResult>( this, "GetPurchases") { Callback = callback }; getPurchases.Call(); } public override void Purchase( string productID, FacebookDelegate<IPurchaseResult> callback, string developerPayload = "") { MethodArguments args = new MethodArguments(); args.AddString("productID", productID); args.AddString("developerPayload", developerPayload); var purchase = new JavaMethodCall<IPurchaseResult>( this, "Purchase") { Callback = callback }; purchase.Call(args); } public override void ConsumePurchase( string purchaseToken, FacebookDelegate<IConsumePurchaseResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("purchaseToken", purchaseToken); var consumePurchase = new JavaMethodCall<IConsumePurchaseResult>( this, "ConsumePurchase") { Callback = callback }; consumePurchase.Call(args); } public override void InitCloudGame( FacebookDelegate<IInitCloudGameResult> callback) { var initCloudGame = new JavaMethodCall<IInitCloudGameResult>( this, "InitCloudGame") { Callback = callback }; initCloudGame.Call(); } public override void GameLoadComplete( FacebookDelegate<IGameLoadCompleteResult> callback) { var gameLoadComplete = new JavaMethodCall<IGameLoadCompleteResult>( this, "GameLoadComplete") { Callback = callback }; gameLoadComplete.Call(); } public override void ScheduleAppToUserNotification( string title, string body, Uri media, int timeInterval, string payload, FacebookDelegate<IScheduleAppToUserNotificationResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("title", title); args.AddString("body", body); args.AddUri("media", media); args.AddPrimative("timeInterval", timeInterval); args.AddString("payload", payload); var scheduleAppToUserNotification = new JavaMethodCall<IScheduleAppToUserNotificationResult>( this, "ScheduleAppToUserNotification") { Callback = callback }; scheduleAppToUserNotification.Call(args); } public override void LoadInterstitialAd( string placementID, FacebookDelegate<IInterstitialAdResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("placementID", placementID); var loadInterstitialAd = new JavaMethodCall<IInterstitialAdResult>( this, "LoadInterstitialAd") { Callback = callback }; loadInterstitialAd.Call(args); } public override void ShowInterstitialAd( string placementID, FacebookDelegate<IInterstitialAdResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("placementID", placementID); var showInterstitialAd = new JavaMethodCall<IInterstitialAdResult>( this, "ShowInterstitialAd") { Callback = callback }; showInterstitialAd.Call(args); } public override void LoadRewardedVideo( string placementID, FacebookDelegate<IRewardedVideoResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("placementID", placementID); var loadRewardedVideo = new JavaMethodCall<IRewardedVideoResult>( this, "LoadRewardedVideo") { Callback = callback }; loadRewardedVideo.Call(args); } public override void ShowRewardedVideo( string placementID, FacebookDelegate<IRewardedVideoResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("placementID", placementID); var showRewardedVideo = new JavaMethodCall<IRewardedVideoResult>( this, "ShowRewardedVideo") { Callback = callback }; showRewardedVideo.Call(args); } public override void GetPayload( FacebookDelegate<IPayloadResult> callback) { var getPayload = new JavaMethodCall<IPayloadResult>( this, "GetPayload") { Callback = callback }; getPayload.Call(); } public override void PostSessionScore(int score, FacebookDelegate<ISessionScoreResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("score", score.ToString()); var postSessionScore = new JavaMethodCall<ISessionScoreResult>( this, "PostSessionScore") { Callback = callback }; postSessionScore.Call(args); } public override void PostTournamentScore(int score, FacebookDelegate<ITournamentScoreResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("score", score.ToString()); var postTournamentScore = new JavaMethodCall<ITournamentScoreResult>( this, "PostTournamentScore") { Callback = callback }; postTournamentScore.Call(args); } public override void GetTournament(FacebookDelegate<ITournamentResult> callback) { var getTournament = new JavaMethodCall<ITournamentResult>( this, "GetTournament") { Callback = callback }; getTournament.Call(); } public override void CreateTournament( int initialScore, string title, string imageBase64DataUrl, string sortOrder, string scoreFormat, Dictionary<string, string> data, FacebookDelegate<ITournamentResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("initialScore", initialScore.ToString()); args.AddString("title", title); args.AddString("imageBase64DataUrl", imageBase64DataUrl); args.AddString("sortOrder", sortOrder); args.AddString("scoreFormat", scoreFormat); args.AddDictionary("data", data.ToDictionary( pair => pair.Key, pair => (object) pair.Value)); var createTournament = new JavaMethodCall<ITournamentResult>( this, "CreateTournament") { Callback = callback }; createTournament.Call(args); } public override void ShareTournament(int score, Dictionary<string, string> data, FacebookDelegate<ITournamentScoreResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("score", score.ToString()); args.AddDictionary("data", data.ToDictionary(pair => pair.Key, pair => (object)pair.Value)); var shareTournament = new JavaMethodCall<ITournamentScoreResult>( this, "ShareTournament") { Callback = callback }; shareTournament.Call(args); } public override void OpenAppStore( FacebookDelegate<IOpenAppStoreResult> callback) { var openAppStore = new JavaMethodCall<IOpenAppStoreResult>( this, "OpenAppStore") { Callback = callback }; openAppStore.Call(); } public override void CreateGamingContext(string playerID, FacebookDelegate<ICreateGamingContextResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("playerID", playerID); var createGamingContext = new JavaMethodCall<ICreateGamingContextResult>( this, "CreateGamingContext") { Callback = callback }; createGamingContext.Call(args); } public override void SwitchGamingContext(string gamingContextID, FacebookDelegate<ISwitchGamingContextResult> callback) { MethodArguments args = new MethodArguments(); args.AddString("gamingContextID", gamingContextID); var switchGamingContext = new JavaMethodCall<ISwitchGamingContextResult>( this, "SwitchGamingContext") { Callback = callback }; switchGamingContext.Call(args); } public override void ChooseGamingContext(List<string> filters, int minSize, int maxSize, FacebookDelegate<IChooseGamingContextResult> callback) { MethodArguments args = new MethodArguments(); args.AddList<string>("filters", filters); args.AddPrimative<int>("minSize", minSize); args.AddPrimative<int>("maxSize", maxSize); var chooseGamingContext = new JavaMethodCall<IChooseGamingContextResult>( this, "ChooseGamingContext") { Callback = callback }; chooseGamingContext.Call(args); } public override void GetCurrentGamingContext(FacebookDelegate<IGetCurrentGamingContextResult> callback) { MethodArguments args = new MethodArguments(); var getCurrentGamingContext = new JavaMethodCall<IGetCurrentGamingContextResult>( this, "GetCurrentGamingContext") { Callback = callback }; getCurrentGamingContext.Call(args); } protected override void SetShareDialogMode(ShareDialogMode mode) { this.CallFB("SetShareDialogMode", mode.ToString()); } private static IAndroidWrapper GetAndroidWrapper() { Assembly assembly = Assembly.Load("Facebook.Unity.Android"); Type type = assembly.GetType("Facebook.Unity.Android.AndroidWrapper"); IAndroidWrapper javaClass = (IAndroidWrapper)Activator.CreateInstance(type); return javaClass; } private void CallFB(string method, string args) { this.androidWrapper.CallStatic(method, args); } private class JavaMethodCall<T> : MethodCall<T> where T : IResult { private AndroidFacebook androidImpl; public JavaMethodCall(AndroidFacebook androidImpl, string methodName) : base(androidImpl, methodName) { this.androidImpl = androidImpl; } public override void Call(MethodArguments args = null) { MethodArguments paramsCopy; if (args == null) { paramsCopy = new MethodArguments(); } else { paramsCopy = new MethodArguments(args); } if (this.Callback != null) { paramsCopy.AddString("callback_id", this.androidImpl.CallbackManager.AddFacebookDelegate(this.Callback)); } this.androidImpl.CallFB(this.MethodName, paramsCopy.ToJsonString()); } } } }