Add async getCurrentUser method. (#180)

* Add async getCurrentUser method.
diff --git a/AUTHORS b/AUTHORS
index 557dff9..efec478 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -4,3 +4,4 @@
 #   Name/Organization <email address>
 
 Google Inc.
+German Saprykin <saprykin.h@gmail.com>
diff --git a/packages/firebase_auth/CHANGELOG.md b/packages/firebase_auth/CHANGELOG.md
index 86195fa..b8d38f7 100644
--- a/packages/firebase_auth/CHANGELOG.md
+++ b/packages/firebase_auth/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.2.0
+
+* **Breaking Change**: Method currentUser is async now.
+
 ## 0.1.2
 
 * Added support for signInWithFacebook
diff --git a/packages/firebase_auth/android/src/main/java/io/flutter/firebaseauth/FirebaseAuthPlugin.java b/packages/firebase_auth/android/src/main/java/io/flutter/firebaseauth/FirebaseAuthPlugin.java
index 585f1fa..ccc1e7a 100755
--- a/packages/firebase_auth/android/src/main/java/io/flutter/firebaseauth/FirebaseAuthPlugin.java
+++ b/packages/firebase_auth/android/src/main/java/io/flutter/firebaseauth/FirebaseAuthPlugin.java
@@ -48,6 +48,9 @@
   @Override
   public void onMethodCall(MethodCall call, Result result) {
     switch (call.method) {
+      case "currentUser":
+        handleCurrentUser(call, result);
+        break;
       case "signInAnonymously":
         handleSignInAnonymously(call, result);
         break;
@@ -75,6 +78,21 @@
     }
   }
 
+  private void handleCurrentUser(MethodCall call, final Result result) {
+    final FirebaseAuth.AuthStateListener listener =
+        new FirebaseAuth.AuthStateListener() {
+          @Override
+          public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
+            firebaseAuth.removeAuthStateListener(this);
+            FirebaseUser user = firebaseAuth.getCurrentUser();
+            ImmutableMap<String, Object> userMap = mapFromUser(user);
+            result.success(userMap);
+          }
+        };
+
+    firebaseAuth.addAuthStateListener(listener);
+  }
+
   private void handleSignInAnonymously(MethodCall call, final Result result) {
     firebaseAuth
         .signInAnonymously()
@@ -156,23 +174,6 @@
       this.result = result;
     }
 
-    private ImmutableMap.Builder<String, Object> userInfoToMap(UserInfo userInfo) {
-      ImmutableMap.Builder<String, Object> builder =
-          ImmutableMap.<String, Object>builder()
-              .put("providerId", userInfo.getProviderId())
-              .put("uid", userInfo.getUid());
-      if (userInfo.getDisplayName() != null) {
-        builder.put("displayName", userInfo.getDisplayName());
-      }
-      if (userInfo.getPhotoUrl() != null) {
-        builder.put("photoUrl", userInfo.getPhotoUrl().toString());
-      }
-      if (userInfo.getEmail() != null) {
-        builder.put("email", userInfo.getEmail());
-      }
-      return builder;
-    }
-
     @Override
     public void onComplete(@NonNull Task<AuthResult> task) {
       if (!task.isSuccessful()) {
@@ -180,23 +181,45 @@
         result.error(ERROR_REASON_EXCEPTION, e.getMessage(), null);
       } else {
         FirebaseUser user = task.getResult().getUser();
-        if (user != null) {
-          ImmutableList.Builder<ImmutableMap<String, Object>> providerDataBuilder =
-              ImmutableList.<ImmutableMap<String, Object>>builder();
-          for (UserInfo userInfo : user.getProviderData()) {
-            providerDataBuilder.add(userInfoToMap(userInfo).build());
-          }
-          ImmutableMap<String, Object> userMap =
-              userInfoToMap(user)
-                  .put("isAnonymous", user.isAnonymous())
-                  .put("isEmailVerified", user.isEmailVerified())
-                  .put("providerData", providerDataBuilder.build())
-                  .build();
-          result.success(userMap);
-        } else {
-          result.success(null);
-        }
+        ImmutableMap<String, Object> userMap = mapFromUser(user);
+        result.success(userMap);
       }
     }
   }
+
+  private ImmutableMap.Builder<String, Object> userInfoToMap(UserInfo userInfo) {
+    ImmutableMap.Builder<String, Object> builder =
+        ImmutableMap.<String, Object>builder()
+            .put("providerId", userInfo.getProviderId())
+            .put("uid", userInfo.getUid());
+    if (userInfo.getDisplayName() != null) {
+      builder.put("displayName", userInfo.getDisplayName());
+    }
+    if (userInfo.getPhotoUrl() != null) {
+      builder.put("photoUrl", userInfo.getPhotoUrl().toString());
+    }
+    if (userInfo.getEmail() != null) {
+      builder.put("email", userInfo.getEmail());
+    }
+    return builder;
+  }
+
+  private ImmutableMap<String, Object> mapFromUser(FirebaseUser user) {
+    if (user != null) {
+      ImmutableList.Builder<ImmutableMap<String, Object>> providerDataBuilder =
+          ImmutableList.<ImmutableMap<String, Object>>builder();
+      for (UserInfo userInfo : user.getProviderData()) {
+        providerDataBuilder.add(userInfoToMap(userInfo).build());
+      }
+      ImmutableMap<String, Object> userMap =
+          userInfoToMap(user)
+              .put("isAnonymous", user.isAnonymous())
+              .put("isEmailVerified", user.isEmailVerified())
+              .put("providerData", providerDataBuilder.build())
+              .build();
+      return userMap;
+    } else {
+      return null;
+    }
+  }
 }
diff --git a/packages/firebase_auth/example/lib/main.dart b/packages/firebase_auth/example/lib/main.dart
index d79ead8..acd8c93 100755
--- a/packages/firebase_auth/example/lib/main.dart
+++ b/packages/firebase_auth/example/lib/main.dart
@@ -41,7 +41,6 @@
   Future<String> _testSignInAnonymously() async {
     final FirebaseUser user = await _auth.signInAnonymously();
     assert(user != null);
-    assert(user == _auth.currentUser);
     assert(user.isAnonymous);
     assert(!user.isEmailVerified);
     assert(await user.getToken() != null);
@@ -57,6 +56,10 @@
       assert(user.providerData[0].photoUrl == null);
       assert(user.providerData[0].email == null);
     }
+
+    final FirebaseUser currentUser = await _auth.currentUser();
+    assert(user.uid == currentUser.uid);
+
     return 'signInAnonymously succeeded: $user';
   }
 
@@ -72,6 +75,10 @@
     assert(user.displayName != null);
     assert(!user.isAnonymous);
     assert(await user.getToken() != null);
+
+    final FirebaseUser currentUser = await _auth.currentUser();
+    assert(user.uid == currentUser.uid);
+
     return 'signInWithGoogle succeeded: $user';
   }
 
diff --git a/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m
index 349c141..6a730ed 100644
--- a/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m
+++ b/packages/firebase_auth/ios/Classes/FirebaseAuthPlugin.m
@@ -50,7 +50,13 @@
 }
 
 - (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
-  if ([@"signInAnonymously" isEqualToString:call.method]) {
+  if ([@"currentUser" isEqualToString:call.method]) {
+    id __block listener = [[FIRAuth auth]
+        addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
+          [self sendResult:result forUser:user error:nil];
+          [auth removeAuthStateDidChangeListener:listener];
+        }];
+  } else if ([@"signInAnonymously" isEqualToString:call.method]) {
     [[FIRAuth auth] signInAnonymouslyWithCompletion:^(FIRUser *user, NSError *error) {
       [self sendResult:result forUser:user error:error];
     }];
diff --git a/packages/firebase_auth/lib/firebase_auth.dart b/packages/firebase_auth/lib/firebase_auth.dart
index 28e21f3..822947f 100755
--- a/packages/firebase_auth/lib/firebase_auth.dart
+++ b/packages/firebase_auth/lib/firebase_auth.dart
@@ -4,12 +4,13 @@
 
 import 'dart:async';
 
-import 'package:meta/meta.dart';
 import 'package:flutter/services.dart';
+import 'package:meta/meta.dart';
 
 /// Represents user data returned from an identity provider.
 class UserInfo {
   final Map<String, dynamic> _data;
+
   UserInfo._(this._data);
 
   /// The provider identifier.
@@ -36,6 +37,7 @@
 /// Represents a user.
 class FirebaseUser extends UserInfo {
   final List<UserInfo> providerData;
+
   FirebaseUser._(Map<String, dynamic> data)
       : providerData = data['providerData']
             .map((Map<String, dynamic> info) => new UserInfo._(info))
@@ -90,8 +92,8 @@
   Future<FirebaseUser> signInAnonymously() async {
     final Map<String, dynamic> data =
         await channel.invokeMethod('signInAnonymously');
-    _currentUser = new FirebaseUser._(data);
-    return _currentUser;
+    final FirebaseUser currentUser = new FirebaseUser._(data);
+    return currentUser;
   }
 
   Future<FirebaseUser> createUserWithEmailAndPassword({
@@ -107,8 +109,8 @@
         'password': password,
       },
     );
-    _currentUser = new FirebaseUser._(data);
-    return _currentUser;
+    final FirebaseUser currentUser = new FirebaseUser._(data);
+    return currentUser;
   }
 
   Future<FirebaseUser> signInWithEmailAndPassword({
@@ -124,8 +126,8 @@
         'password': password,
       },
     );
-    _currentUser = new FirebaseUser._(data);
-    return _currentUser;
+    final FirebaseUser currentUser = new FirebaseUser._(data);
+    return currentUser;
   }
 
   Future<FirebaseUser> signInWithFacebook(
@@ -135,8 +137,8 @@
         await channel.invokeMethod('signInWithFacebook', <String, String>{
       'accessToken': accessToken,
     });
-    _currentUser = new FirebaseUser._(data);
-    return _currentUser;
+    final FirebaseUser currentUser = new FirebaseUser._(data);
+    return currentUser;
   }
 
   Future<FirebaseUser> signInWithGoogle({
@@ -152,17 +154,19 @@
         'accessToken': accessToken,
       },
     );
-    _currentUser = new FirebaseUser._(data);
-    return _currentUser;
+    final FirebaseUser currentUser = new FirebaseUser._(data);
+    return currentUser;
   }
 
   Future<Null> signOut() async {
-    await channel.invokeMethod("signOut");
-    _currentUser = null;
+    return await channel.invokeMethod("signOut");
   }
 
-  FirebaseUser _currentUser;
-
-  /// Synchronously gets the cached current user, or `null` if there is none.
-  FirebaseUser get currentUser => _currentUser;
+  /// Asynchronously gets current user, or `null` if there is none.
+  Future<FirebaseUser> currentUser() async {
+    final Map<String, dynamic> data = await channel.invokeMethod("currentUser");
+    final FirebaseUser currentUser =
+        data == null ? null : new FirebaseUser._(data);
+    return currentUser;
+  }
 }
diff --git a/packages/firebase_auth/pubspec.yaml b/packages/firebase_auth/pubspec.yaml
index 44beae7..a12c6c0 100755
--- a/packages/firebase_auth/pubspec.yaml
+++ b/packages/firebase_auth/pubspec.yaml
@@ -3,7 +3,7 @@
 description: Firebase Auth plugin for Flutter.
 author: Flutter Team <flutter-dev@googlegroups.com>
 homepage: https://github.com/flutter/plugins/tree/master/packages/firebase_auth
-version: 0.1.2
+version: 0.2.0
 
 flutter:
   plugin:
diff --git a/packages/firebase_auth/test/firebase_auth_test.dart b/packages/firebase_auth/test/firebase_auth_test.dart
index 39c26f3..99f13f0 100755
--- a/packages/firebase_auth/test/firebase_auth_test.dart
+++ b/packages/firebase_auth/test/firebase_auth_test.dart
@@ -50,7 +50,6 @@
     });
     void verifyUser(FirebaseUser user) {
       expect(user, isNotNull);
-      expect(user, auth.currentUser);
       expect(user.isAnonymous, isTrue);
       expect(user.isEmailVerified, isFalse);
       expect(user.providerData.length, 1);
@@ -62,6 +61,17 @@
       expect(userInfo.email, kMockEmail);
     }
 
+    test('currentUser', () async {
+      final FirebaseUser user = await auth.currentUser();
+      verifyUser(user);
+      expect(
+        log,
+        equals(<MethodCall>[
+          const MethodCall('currentUser'),
+        ]),
+      );
+    });
+
     test('signInAnonymously', () async {
       final FirebaseUser user = await auth.signInAnonymously();
       verifyUser(user);