Skip to content

Commit 1c98d10

Browse files
authored
Merge pull request flutter#5 from flutter/master
Update master
2 parents e2613e0 + 6c341f8 commit 1c98d10

File tree

17 files changed

+156
-105
lines changed

17 files changed

+156
-105
lines changed

packages/camera/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.5.4+2
2+
3+
* Fix Android NullPointerException on devices with only front-facing camera.
4+
15
## 0.5.4+1
26

37
* Fix Android pause and resume video crash when executing in APIs below 24.

packages/camera/android/src/main/java/io/flutter/plugins/camera/CameraUtils.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,32 +77,31 @@ static CamcorderProfile getBestAvailableCamcorderProfileForResolutionPreset(
7777
// All of these cases deliberately fall through to get the best available profile.
7878
case max:
7979
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_HIGH)) {
80-
return CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
80+
return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_HIGH);
8181
}
8282
case ultraHigh:
8383
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_2160P)) {
84-
return CamcorderProfile.get(CamcorderProfile.QUALITY_2160P);
84+
return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_2160P);
8585
}
8686
case veryHigh:
8787
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_1080P)) {
88-
return CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
88+
return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_1080P);
8989
}
9090
case high:
9191
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_720P)) {
92-
return CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
92+
return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_720P);
9393
}
9494
case medium:
9595
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_480P)) {
96-
return CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
96+
return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_480P);
9797
}
9898
case low:
9999
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_QVGA)) {
100-
return CamcorderProfile.get(CamcorderProfile.QUALITY_QVGA);
100+
return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_QVGA);
101101
}
102102
default:
103-
if (CamcorderProfile.hasProfile(
104-
Integer.parseInt(cameraName), CamcorderProfile.QUALITY_LOW)) {
105-
return CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);
103+
if (CamcorderProfile.hasProfile(cameraId, CamcorderProfile.QUALITY_LOW)) {
104+
return CamcorderProfile.get(cameraId, CamcorderProfile.QUALITY_LOW);
106105
} else {
107106
throw new IllegalArgumentException(
108107
"No capture session available for current capture session.");

packages/camera/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: camera
22
description: A Flutter plugin for getting information about and controlling the
33
camera on Android and iOS. Supports previewing the camera feed, capturing images, capturing video,
44
and streaming image buffers to dart.
5-
version: 0.5.4+1
5+
version: 0.5.4+2
66

77
authors:
88
- Flutter Team <[email protected]>

packages/google_maps_flutter/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.5.21+2
2+
3+
* Fix more `prefer_const_constructors` analyzer warnings in example app.
4+
15
## 0.5.21+1
26

37
* Fix `prefer_const_constructors` analyzer warnings in example app.

packages/google_maps_flutter/example/lib/padding.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class MarkerIconsBodyState extends State<MarkerIconsBody> {
9898
),
9999
),
100100
),
101-
Spacer(),
101+
const Spacer(),
102102
Flexible(
103103
flex: 2,
104104
child: TextField(
@@ -110,7 +110,7 @@ class MarkerIconsBodyState extends State<MarkerIconsBody> {
110110
),
111111
),
112112
),
113-
Spacer(),
113+
const Spacer(),
114114
Flexible(
115115
flex: 2,
116116
child: TextField(
@@ -122,7 +122,7 @@ class MarkerIconsBodyState extends State<MarkerIconsBody> {
122122
),
123123
),
124124
),
125-
Spacer(),
125+
const Spacer(),
126126
Flexible(
127127
flex: 2,
128128
child: TextField(

packages/google_maps_flutter/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: google_maps_flutter
22
description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
33
author: Flutter Team <[email protected]>
44
homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter
5-
version: 0.5.21+1
5+
version: 0.5.21+2
66

77
dependencies:
88
flutter:

packages/google_sign_in/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 4.0.8
2+
3+
* Get rid of `MethodCompleter` and serialize async actions using chained futures.
4+
This prevents a bug when sign in methods are being used in error handling zones.
5+
16
## 4.0.7
27

38
* Switch from using `api` to `implementation` for dependency on `play-services-auth`,

packages/google_sign_in/lib/google_sign_in.dart

100755100644
Lines changed: 53 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -230,50 +230,57 @@ class GoogleSignIn {
230230
}
231231

232232
Future<void> _ensureInitialized() {
233-
if (_initialization == null) {
234-
_initialization = channel.invokeMethod<void>('init', <String, dynamic>{
235-
'signInOption': (signInOption ?? SignInOption.standard).toString(),
236-
'scopes': scopes ?? <String>[],
237-
'hostedDomain': hostedDomain,
238-
})
239-
..catchError((dynamic _) {
240-
// Invalidate initialization if it errored out.
241-
_initialization = null;
242-
});
243-
}
244-
return _initialization;
233+
return _initialization ??=
234+
channel.invokeMethod<void>('init', <String, dynamic>{
235+
'signInOption': (signInOption ?? SignInOption.standard).toString(),
236+
'scopes': scopes ?? <String>[],
237+
'hostedDomain': hostedDomain,
238+
})
239+
..catchError((dynamic _) {
240+
// Invalidate initialization if it errored out.
241+
_initialization = null;
242+
});
245243
}
246244

247-
/// Keeps track of the most recently scheduled method call.
248-
_MethodCompleter _lastMethodCompleter;
245+
/// The most recently scheduled method call.
246+
Future<void> _lastMethodCall;
247+
248+
/// Returns a [Future] that completes with a success after [future], whether
249+
/// it completed with a value or an error.
250+
static Future<void> _waitFor(Future<void> future) {
251+
final Completer<void> completer = Completer<void>();
252+
future.whenComplete(completer.complete).catchError((dynamic _) {
253+
// Ignore if previous call completed with an error.
254+
});
255+
return completer.future;
256+
}
249257

250258
/// Adds call to [method] in a queue for execution.
251259
///
252260
/// At most one in flight call is allowed to prevent concurrent (out of order)
253261
/// updates to [currentUser] and [onCurrentUserChanged].
254-
Future<GoogleSignInAccount> _addMethodCall(String method) {
255-
if (_lastMethodCompleter == null) {
256-
_lastMethodCompleter = _MethodCompleter(method)
257-
..complete(_callMethod(method));
258-
return _lastMethodCompleter.future;
262+
Future<GoogleSignInAccount> _addMethodCall(String method) async {
263+
Future<GoogleSignInAccount> response;
264+
if (_lastMethodCall == null) {
265+
response = _callMethod(method);
266+
} else {
267+
response = _lastMethodCall.then((_) {
268+
// If after the last completed call `currentUser` is not `null` and requested
269+
// method is a sign in method, re-use the same authenticated user
270+
// instead of making extra call to the native side.
271+
const List<String> kSignInMethods = <String>[
272+
'signIn',
273+
'signInSilently'
274+
];
275+
if (kSignInMethods.contains(method) && _currentUser != null) {
276+
return _currentUser;
277+
} else {
278+
return _callMethod(method);
279+
}
280+
});
259281
}
260-
261-
final _MethodCompleter completer = _MethodCompleter(method);
262-
_lastMethodCompleter.future.whenComplete(() {
263-
// If after the last completed call currentUser is not null and requested
264-
// method is a sign in method, re-use the same authenticated user
265-
// instead of making extra call to the native side.
266-
const List<String> kSignInMethods = <String>['signIn', 'signInSilently'];
267-
if (kSignInMethods.contains(method) && _currentUser != null) {
268-
completer.complete(_currentUser);
269-
} else {
270-
completer.complete(_callMethod(method));
271-
}
272-
}).catchError((dynamic _) {
273-
// Ignore if previous call completed with an error.
274-
});
275-
_lastMethodCompleter = completer;
276-
return _lastMethodCompleter.future;
282+
_lastMethodCall = _waitFor(response);
283+
return response;
277284
}
278285

279286
/// The currently signed in account, or null if the user is signed out.
@@ -296,12 +303,17 @@ class GoogleSignIn {
296303
/// returned Future completes with [PlatformException] whose `code` can be
297304
/// either [kSignInRequiredError] (when there is no authenticated user) or
298305
/// [kSignInFailedError] (when an unknown error occurred).
299-
Future<GoogleSignInAccount> signInSilently({bool suppressErrors = true}) {
300-
final Future<GoogleSignInAccount> result = _addMethodCall('signInSilently');
301-
if (suppressErrors) {
302-
return result.catchError((dynamic _) => null);
306+
Future<GoogleSignInAccount> signInSilently(
307+
{bool suppressErrors = true}) async {
308+
try {
309+
return await _addMethodCall('signInSilently');
310+
} catch (_) {
311+
if (suppressErrors) {
312+
return null;
313+
} else {
314+
rethrow;
315+
}
303316
}
304-
return result;
305317
}
306318

307319
/// Returns a future that resolves to whether a user is currently signed in.
@@ -334,26 +346,3 @@ class GoogleSignIn {
334346
/// authentication.
335347
Future<GoogleSignInAccount> disconnect() => _addMethodCall('disconnect');
336348
}
337-
338-
class _MethodCompleter {
339-
_MethodCompleter(this.method);
340-
341-
final String method;
342-
final Completer<GoogleSignInAccount> _completer =
343-
Completer<GoogleSignInAccount>();
344-
345-
Future<void> complete(FutureOr<GoogleSignInAccount> value) async {
346-
if (value is Future<GoogleSignInAccount>) {
347-
try {
348-
_completer.complete(await value);
349-
} catch (e, stacktrace) {
350-
_completer.completeError(e, stacktrace);
351-
}
352-
} else {
353-
_completer.complete(value);
354-
}
355-
}
356-
357-
bool get isCompleted => _completer.isCompleted;
358-
Future<GoogleSignInAccount> get future => _completer.future;
359-
}

packages/google_sign_in/pubspec.yaml

100755100644
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ description: Flutter plugin for Google Sign-In, a secure authentication system
33
for signing in with a Google account on Android and iOS.
44
author: Flutter Team <[email protected]>
55
homepage: https://github.com/flutter/plugins/tree/master/packages/google_sign_in
6-
version: 4.0.7
6+
version: 4.0.8
77

88
flutter:
99
plugin:

packages/google_sign_in/test/google_sign_in_test.dart

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,11 @@ void main() {
4545
responses = Map<String, dynamic>.from(kDefaultResponses);
4646
channel.setMockMethodCallHandler((MethodCall methodCall) {
4747
log.add(methodCall);
48-
return Future<dynamic>.value(responses[methodCall.method]);
48+
final dynamic response = responses[methodCall.method];
49+
if (response != null && response is Exception) {
50+
return Future<dynamic>.error('$response');
51+
}
52+
return Future<dynamic>.value(response);
4953
});
5054
googleSignIn = GoogleSignIn();
5155
log.clear();
@@ -142,6 +146,27 @@ void main() {
142146
]);
143147
});
144148

149+
test('signIn works even if a previous call throws error in other zone',
150+
() async {
151+
responses['signInSilently'] = Exception('Not a user');
152+
await runZoned(() async {
153+
expect(await googleSignIn.signInSilently(), isNull);
154+
}, onError: (dynamic e, dynamic st) {});
155+
expect(await googleSignIn.signIn(), isNotNull);
156+
expect(
157+
log,
158+
<Matcher>[
159+
isMethodCall('init', arguments: <String, dynamic>{
160+
'signInOption': 'SignInOption.standard',
161+
'scopes': <String>[],
162+
'hostedDomain': null,
163+
}),
164+
isMethodCall('signInSilently', arguments: null),
165+
isMethodCall('signIn', arguments: null),
166+
],
167+
);
168+
});
169+
145170
test('concurrent calls of the same method trigger sign in once', () async {
146171
final List<Future<GoogleSignInAccount>> futures =
147172
<Future<GoogleSignInAccount>>[
@@ -170,7 +195,7 @@ void main() {
170195
});
171196

172197
test('can sign in after previously failed attempt', () async {
173-
responses['signInSilently'] = <String, dynamic>{'error': 'Not a user'};
198+
responses['signInSilently'] = Exception('Not a user');
174199
expect(await googleSignIn.signInSilently(), isNull);
175200
expect(await googleSignIn.signIn(), isNotNull);
176201
expect(

packages/url_launcher/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
2+
## 5.1.3
3+
4+
* Always launch url from the top most UIViewController in iOS.
5+
16
## 5.1.2
27

38
* Update AGP and gradle.

0 commit comments

Comments
 (0)