001package com.gigya.android.sdk.providers.provider; 002 003import android.app.Activity; 004import android.content.Context; 005import android.content.Intent; 006import android.os.Bundle; 007import android.support.annotation.NonNull; 008import android.support.annotation.Nullable; 009import android.support.v7.app.AppCompatActivity; 010 011import com.gigya.android.sdk.GigyaLogger; 012import com.gigya.android.sdk.api.IBusinessApiService; 013import com.gigya.android.sdk.persistence.IPersistenceService; 014import com.gigya.android.sdk.ui.HostActivity; 015import com.gigya.android.sdk.utils.FileUtils; 016import com.google.android.gms.auth.api.signin.GoogleSignIn; 017import com.google.android.gms.auth.api.signin.GoogleSignInAccount; 018import com.google.android.gms.auth.api.signin.GoogleSignInClient; 019import com.google.android.gms.auth.api.signin.GoogleSignInOptions; 020import com.google.android.gms.auth.api.signin.GoogleSignInStatusCodes; 021import com.google.android.gms.common.ConnectionResult; 022import com.google.android.gms.common.GoogleApiAvailability; 023import com.google.android.gms.common.api.ApiException; 024import com.google.android.gms.tasks.OnCompleteListener; 025import com.google.android.gms.tasks.Task; 026 027import org.json.JSONObject; 028 029import java.util.Map; 030 031import static com.gigya.android.sdk.GigyaDefinitions.Providers.GOOGLE; 032 033public class GoogleProvider extends Provider { 034 035 private static final int RC_SIGN_IN = 0; 036 private GoogleSignInClient _googleClient; 037 private String _clientId; 038 039 final private FileUtils _fileUtils; 040 041 public GoogleProvider(Context context, 042 IPersistenceService persistenceService, 043 IBusinessApiService businessApiService, 044 ProviderCallback providerCallback, 045 FileUtils fileUtils) { 046 super(context, persistenceService, businessApiService, providerCallback); 047 _fileUtils = fileUtils; 048 } 049 050 @Override 051 public String getName() { 052 return GOOGLE; 053 } 054 055 public static boolean isAvailable(Context context) { 056 try { 057 Class.forName("com.google.android.gms.auth.api.signin.GoogleSignInClient"); 058 return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS; 059 } catch (Throwable t) { 060 return false; 061 } 062 } 063 064 @Override 065 public void login(final Map<String, Object> loginParams, final String loginMode) { 066 if (_connecting) { 067 return; 068 } 069 _connecting = true; 070 _loginMode = loginMode; 071 try { 072 _clientId = _fileUtils.stringFromMetaData("googleClientId"); 073 } catch (Exception ex) { 074 _connecting = false; 075 ex.printStackTrace(); 076 } 077 if (_clientId == null) { 078 onLoginFailed("Missing server client id. Check manifest implementation"); 079 return; 080 } 081 GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 082 .requestServerAuthCode(_clientId) 083 .requestEmail() 084 .build(); 085 _googleClient = GoogleSignIn.getClient(_context, gso); 086 087 GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(_context); 088 if (account != null) { 089 // This option should not happen theoretically because we logout out explicitly. 090 onLoginSuccess(loginParams, getProviderSessions(account.getServerAuthCode(), -1L, null), loginMode); 091 finish(null); 092 return; 093 } 094 095 HostActivity.present(_context, new HostActivity.HostActivityLifecycleCallbacks() { 096 097 @Override 098 public void onCreate(AppCompatActivity activity, @Nullable Bundle savedInstanceState) { 099 Intent signInIntent = _googleClient.getSignInIntent(); 100 activity.startActivityForResult(signInIntent, RC_SIGN_IN); 101 } 102 103 @Override 104 public void onActivityResult(AppCompatActivity activity, int requestCode, int resultCode, @Nullable Intent data) { 105 if (requestCode == RC_SIGN_IN) { 106 Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data); 107 handleSignInResult(loginParams, activity, task); 108 } 109 } 110 }); 111 } 112 113 private void handleSignInResult(final Map<String, Object> loginParams, AppCompatActivity activity, Task<GoogleSignInAccount> completedTask) { 114 try { 115 GoogleSignInAccount account = completedTask.getResult(ApiException.class); 116 if (account == null) { 117 onLoginFailed("Account unavailable"); 118 } else { 119 /* Fetch server auth code */ 120 final String authCode = account.getServerAuthCode(); 121 if (authCode == null) { 122 onLoginFailed("Id token no available"); 123 } else { 124 onLoginSuccess(loginParams, getProviderSessions(authCode, -1L, null), _loginMode); 125 } 126 } 127 finish(activity); 128 } catch (ApiException e) { 129 final int exceptionStatusCode = e.getStatusCode(); 130 switch (exceptionStatusCode) { 131 case GoogleSignInStatusCodes.SIGN_IN_CANCELLED: 132 onCanceled(); 133 break; 134 case GoogleSignInStatusCodes.SIGN_IN_FAILED: 135 default: 136 onLoginFailed(GoogleSignInStatusCodes.getStatusCodeString(exceptionStatusCode)); 137 break; 138 } 139 finish(activity); 140 } 141 } 142 143 @Override 144 public void logout() { 145 super.logout(); 146 if (_googleClient == null) { 147 if (_clientId == null) { 148 GigyaLogger.error("GoogleLoginProvider", "provider client id unavailable for logout"); 149 return; 150 } 151 GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) 152 .requestServerAuthCode(_clientId) 153 .requestEmail() 154 .build(); 155 _googleClient = GoogleSignIn.getClient(_context, gso); 156 } 157 _googleClient.signOut(); 158 } 159 160 @Override 161 public String getProviderSessions(String tokenOrCode, long expiration, String uid) { 162 // code is relevant. 163 try { 164 return new JSONObject() 165 .put(getName(), new JSONObject() 166 .put("code", tokenOrCode)).toString(); 167 } catch (Exception ex) { 168 _connecting = false; 169 ex.printStackTrace(); 170 } 171 return null; 172 } 173 174 @Override 175 public boolean supportsTokenTracking() { 176 return false; 177 } 178 179 @Override 180 public void trackTokenChange() { 181 // Stub. 182 } 183 184 private void finish(final Activity activity) { 185 if (_googleClient != null) { 186 _googleClient.signOut().addOnCompleteListener(new OnCompleteListener<Void>() { 187 @Override 188 public void onComplete(@NonNull Task<Void> task) { 189 if (activity != null) { 190 activity.finish(); 191 } 192 } 193 }); 194 } else { 195 if (activity != null) { 196 activity.finish(); 197 } 198 } 199 } 200}