22
33import android .content .Intent ;
44import android .content .pm .ApplicationInfo ;
5+ import android .net .Uri ;
56import android .os .Bundle ;
67import android .util .Log ;
78import android .view .Menu ;
3738import com .facebook .login .widget .LoginButton ;
3839import com .github .florent37 .inlineactivityresult .rx .RxInlineActivityResult ;
3940import com .google .android .gms .auth .api .signin .GoogleSignIn ;
41+ import com .google .android .gms .auth .api .signin .GoogleSignInAccount ;
4042import com .google .android .gms .auth .api .signin .GoogleSignInClient ;
4143import com .google .android .gms .auth .api .signin .GoogleSignInOptions ;
44+ import com .google .android .gms .common .ConnectionResult ;
45+ import com .google .android .gms .common .GoogleApiAvailability ;
4246import com .google .firebase .FirebaseApp ;
4347import com .yarolegovich .lovelydialog .LovelyTextInputDialog ;
4448
49+ import net .openid .appauth .AuthorizationRequest ;
50+ import net .openid .appauth .AuthorizationResponse ;
51+ import net .openid .appauth .AuthorizationService ;
52+ import net .openid .appauth .AuthorizationServiceConfiguration ;
53+ import net .openid .appauth .ClientSecretBasic ;
54+ import net .openid .appauth .ResponseTypeValues ;
55+
4556import butterknife .BindView ;
4657import hu .akarnokd .rxjava3 .bridge .RxJavaBridge ;
4758import io .reactivex .rxjava3 .android .schedulers .AndroidSchedulers ;
4859import io .reactivex .rxjava3 .core .Completable ;
60+ import io .reactivex .rxjava3 .core .Observable ;
4961import io .reactivex .rxjava3 .core .Single ;
5062import io .reactivex .rxjava3 .functions .Consumer ;
5163import io .reactivex .rxjava3 .internal .functions .Functions ;
@@ -66,6 +78,7 @@ public class LoginActivity extends BaseActivity {
6678
6779 private final CallbackManager facebookCallbackManager = CallbackManager .Factory .create ();
6880 private GoogleSignInClient googleSignInClient ;
81+ private AuthorizationService appAuthService ;
6982
7083 private FirebaseAuth firebaseAuth ;
7184
@@ -75,6 +88,13 @@ protected int getActivityLayoutRes() {
7588 return R .layout .activity_login ;
7689 }
7790
91+ private AuthorizationService getAppAuthService () {
92+ if (appAuthService == null ) {
93+ appAuthService = new AuthorizationService (this );
94+ }
95+ return appAuthService ;
96+ }
97+
7898 @ Override
7999 protected void onCreate (@ Nullable Bundle savedInstanceState ) {
80100 super .onCreate (savedInstanceState );
@@ -353,6 +373,52 @@ public void onSuccess(LoginResult loginResult) {
353373 });
354374 }
355375
376+ private Observable <String > getGoogleIdTokenBySdk () {
377+ return new RxInlineActivityResult (this )
378+ .request (googleSignInClient .getSignInIntent ())
379+ .map (result -> GoogleSignIn .getSignedInAccountFromIntent (result .getData ()).getResult ())
380+ .map (GoogleSignInAccount ::getIdToken )
381+ .as (RxJavaBridge .toV3Observable ());
382+ }
383+
384+ private Observable <String > getGoogleIdTokenByChromeCustomTab () {
385+ AuthorizationServiceConfiguration asc = new AuthorizationServiceConfiguration (
386+ Uri .parse ("https://accounts.google.com/o/oauth2/v2/auth" ),
387+ Uri .parse ("https://www.googleapis.com/oauth2/v4/token" )
388+ );
389+
390+ String clientId = getString (R .string .default_web_client_id );
391+ Uri redirectUri = new Uri .Builder ()
392+ .scheme (getString (R .string .auth_google_scheme ))
393+ .authority (getString (R .string .auth_google_host ))
394+ .path (getString (R .string .auth_google_path ))
395+ .build ();
396+ AuthorizationRequest .Builder builder = new AuthorizationRequest .Builder (asc , clientId , ResponseTypeValues .CODE , redirectUri )
397+ .setScopes ("profile email" )
398+ .setPrompt (AuthorizationRequest .Prompt .LOGIN );
399+
400+ AuthorizationService service = getAppAuthService ();
401+ return new RxInlineActivityResult (this )
402+ .request (service .getAuthorizationRequestIntent (builder .build ()))
403+ .flatMap (result -> {
404+ Intent data = result .getData ();
405+ Throwable cause = result .getCause ();
406+ return data != null ? io .reactivex .Observable .just (data ) : io .reactivex .Observable .error (cause != null ? cause : new UnknownError ());
407+ })
408+ .map (AuthorizationResponse ::fromIntent )
409+ .flatMap (authResponse -> io .reactivex .Observable .<String >create (emitter -> service .performTokenRequest (
410+ authResponse .createTokenExchangeRequest (),
411+ new ClientSecretBasic (BuildConfig .GOOGLE_CLIENT_SECRET ),
412+ (tokenResponse , e ) -> {
413+ if (tokenResponse != null ) {
414+ emitter .onNext (tokenResponse .idToken );
415+ } else {
416+ emitter .onError (e );
417+ }
418+ })))
419+ .as (RxJavaBridge .toV3Observable ());
420+ }
421+
356422 private void setupSignInWithGoogleButton (FirebaseAuth firebaseAuth ) {
357423 setupButton (firebaseAuth ,
358424 signInWithGoogleButton ,
@@ -362,24 +428,22 @@ private void setupSignInWithGoogleButton(FirebaseAuth firebaseAuth) {
362428 onDestroy .add (unlinkProvider (user , signInWithGoogleButton , Provider .GOOGLE , R .string .google )
363429 .subscribe (() -> {}, RxUtil .ON_ERROR_LOG_V3 ));
364430 } else {
365- onDestroy .add (RxJavaBridge
366- .toV3Disposable (new RxInlineActivityResult (this )
367- .request (googleSignInClient .getSignInIntent ())
368- .map (result -> {
369- Intent data = result .getData ();
370- return GoogleSignIn .getSignedInAccountFromIntent (data )
371- .getResult ();
372- })
373- .flatMapSingle (account -> {
374- String token = account .getIdToken ();
375- IdpAuthCredential credential = GoogleAuthProvider .getCredential (token );
376- return RxJavaBridge .toV2Single (firebaseAuth .signInWithCredential (credential ));
377- })
378- .doOnError (e -> {
379- dialog (e );
380- googleSignInClient .signOut ();
381- })
382- .subscribe (io .reactivex .internal .functions .Functions .emptyConsumer (), RxUtil .ON_ERROR_LOG_V2 )));
431+ final boolean hasGms = ConnectionResult .SUCCESS == GoogleApiAvailability .getInstance ()
432+ .isGooglePlayServicesAvailable (this );
433+ Observable <String > getGoogleIdToken = hasGms
434+ ? getGoogleIdTokenBySdk ()
435+ : getGoogleIdTokenByChromeCustomTab ();
436+ //noinspection ResultOfMethodCallIgnored
437+ getGoogleIdToken .doOnSubscribe (onDestroy ::add )
438+ .flatMapSingle (token -> {
439+ IdpAuthCredential credential = GoogleAuthProvider .getCredential (token );
440+ return firebaseAuth .signInWithCredential (credential );
441+ })
442+ .doOnError (e -> {
443+ dialog (e );
444+ googleSignInClient .signOut ();
445+ })
446+ .subscribe (Functions .emptyConsumer (), RxUtil .ON_ERROR_LOG_V3 );
383447 }
384448 },
385449 auth -> {
0 commit comments