20
20
import static io .flutter .plugins .inapppurchase .MethodCallHandlerImpl .MethodNames .QUERY_PURCHASE_HISTORY_ASYNC ;
21
21
import static io .flutter .plugins .inapppurchase .MethodCallHandlerImpl .MethodNames .SHOW_ALTERNATIVE_BILLING_ONLY_INFORMATION_DIALOG ;
22
22
import static io .flutter .plugins .inapppurchase .MethodCallHandlerImpl .MethodNames .START_CONNECTION ;
23
+ import static io .flutter .plugins .inapppurchase .MethodCallHandlerImpl .MethodNames .USER_SELECTED_ALTERNATIVE_BILLING ;
23
24
import static io .flutter .plugins .inapppurchase .PluginPurchaseListener .ON_PURCHASES_UPDATED ;
24
25
import static io .flutter .plugins .inapppurchase .Translator .fromAlternativeBillingOnlyReportingDetails ;
25
26
import static io .flutter .plugins .inapppurchase .Translator .fromBillingConfig ;
26
27
import static io .flutter .plugins .inapppurchase .Translator .fromBillingResult ;
27
28
import static io .flutter .plugins .inapppurchase .Translator .fromProductDetailsList ;
28
29
import static io .flutter .plugins .inapppurchase .Translator .fromPurchaseHistoryRecordList ;
29
30
import static io .flutter .plugins .inapppurchase .Translator .fromPurchasesList ;
31
+ import static io .flutter .plugins .inapppurchase .Translator .fromUserChoiceDetails ;
30
32
import static java .util .Arrays .asList ;
31
33
import static java .util .Collections .singletonList ;
32
34
import static java .util .Collections .unmodifiableList ;
73
75
import com .android .billingclient .api .QueryProductDetailsParams ;
74
76
import com .android .billingclient .api .QueryPurchaseHistoryParams ;
75
77
import com .android .billingclient .api .QueryPurchasesParams ;
78
+ import com .android .billingclient .api .UserChoiceBillingListener ;
79
+ import com .android .billingclient .api .UserChoiceDetails ;
76
80
import io .flutter .embedding .engine .plugins .activity .ActivityPluginBinding ;
77
81
import io .flutter .plugin .common .MethodCall ;
78
82
import io .flutter .plugin .common .MethodChannel ;
82
86
import java .lang .reflect .Constructor ;
83
87
import java .lang .reflect .InvocationTargetException ;
84
88
import java .util .ArrayList ;
89
+ import java .util .Collections ;
85
90
import java .util .HashMap ;
86
91
import java .util .List ;
87
92
import java .util .Map ;
92
97
import org .mockito .ArgumentCaptor ;
93
98
import org .mockito .Captor ;
94
99
import org .mockito .Mock ;
100
+ import org .mockito .Mockito ;
95
101
import org .mockito .MockitoAnnotations ;
96
102
import org .mockito .Spy ;
97
103
import org .mockito .stubbing .Answer ;
@@ -107,15 +113,23 @@ public class MethodCallHandlerTest {
107
113
@ Mock ActivityPluginBinding mockActivityPluginBinding ;
108
114
@ Captor ArgumentCaptor <HashMap <String , Object >> resultCaptor ;
109
115
116
+ private final int DEFAULT_HANDLE = 1 ;
117
+
110
118
@ Before
111
119
public void setUp () {
112
120
MockitoAnnotations .openMocks (this );
113
121
// Use the same client no matter if alternative billing is enabled or not.
114
122
when (factory .createBillingClient (
115
- context , mockMethodChannel , BillingChoiceMode .PLAY_BILLING_ONLY ))
123
+ context , mockMethodChannel , BillingChoiceMode .PLAY_BILLING_ONLY , null ))
124
+ .thenReturn (mockBillingClient );
125
+ when (factory .createBillingClient (
126
+ context , mockMethodChannel , BillingChoiceMode .ALTERNATIVE_BILLING_ONLY , null ))
116
127
.thenReturn (mockBillingClient );
117
128
when (factory .createBillingClient (
118
- context , mockMethodChannel , BillingChoiceMode .ALTERNATIVE_BILLING_ONLY ))
129
+ any (Context .class ),
130
+ any (MethodChannel .class ),
131
+ eq (BillingChoiceMode .USER_CHOICE_BILLING ),
132
+ any (UserChoiceBillingListener .class )))
119
133
.thenReturn (mockBillingClient );
120
134
methodChannelHandler = new MethodCallHandlerImpl (activity , context , mockMethodChannel , factory );
121
135
when (mockActivityPluginBinding .getActivity ()).thenReturn (activity );
@@ -164,7 +178,7 @@ public void startConnection() {
164
178
mockStartConnection (BillingChoiceMode .PLAY_BILLING_ONLY );
165
179
verify (result , never ()).success (any ());
166
180
verify (factory , times (1 ))
167
- .createBillingClient (context , mockMethodChannel , BillingChoiceMode .PLAY_BILLING_ONLY );
181
+ .createBillingClient (context , mockMethodChannel , BillingChoiceMode .PLAY_BILLING_ONLY , null );
168
182
169
183
BillingResult billingResult =
170
184
BillingResult .newBuilder ()
@@ -183,7 +197,7 @@ public void startConnectionAlternativeBillingOnly() {
183
197
verify (result , never ()).success (any ());
184
198
verify (factory , times (1 ))
185
199
.createBillingClient (
186
- context , mockMethodChannel , BillingChoiceMode .ALTERNATIVE_BILLING_ONLY );
200
+ context , mockMethodChannel , BillingChoiceMode .ALTERNATIVE_BILLING_ONLY , null );
187
201
188
202
BillingResult billingResult =
189
203
BillingResult .newBuilder ()
@@ -209,7 +223,7 @@ public void startConnectionAlternativeBillingUnset() {
209
223
methodChannelHandler .onMethodCall (call , result );
210
224
verify (result , never ()).success (any ());
211
225
verify (factory , times (1 ))
212
- .createBillingClient (context , mockMethodChannel , BillingChoiceMode .PLAY_BILLING_ONLY );
226
+ .createBillingClient (context , mockMethodChannel , BillingChoiceMode .PLAY_BILLING_ONLY , null );
213
227
214
228
BillingResult billingResult =
215
229
BillingResult .newBuilder ()
@@ -221,6 +235,106 @@ public void startConnectionAlternativeBillingUnset() {
221
235
verify (result , times (1 )).success (fromBillingResult (billingResult ));
222
236
}
223
237
238
+ @ Test
239
+ public void startConnectionUserChoiceBilling () {
240
+ ArgumentCaptor <BillingClientStateListener > captor =
241
+ mockStartConnection (BillingChoiceMode .USER_CHOICE_BILLING );
242
+ ArgumentCaptor <UserChoiceBillingListener > billingCaptor =
243
+ ArgumentCaptor .forClass (UserChoiceBillingListener .class );
244
+ verify (result , never ()).success (any ());
245
+ verify (factory , times (1 ))
246
+ .createBillingClient (
247
+ any (Context .class ),
248
+ any (MethodChannel .class ),
249
+ eq (BillingChoiceMode .USER_CHOICE_BILLING ),
250
+ billingCaptor .capture ());
251
+
252
+ BillingResult billingResult =
253
+ BillingResult .newBuilder ()
254
+ .setResponseCode (100 )
255
+ .setDebugMessage ("dummy debug message" )
256
+ .build ();
257
+ captor .getValue ().onBillingSetupFinished (billingResult );
258
+
259
+ verify (result , times (1 )).success (fromBillingResult (billingResult ));
260
+ UserChoiceDetails details = mock (UserChoiceDetails .class );
261
+ final String externalTransactionToken = "someLongTokenId1234" ;
262
+ final String originalTransactionId = "originalTransactionId123456" ;
263
+ when (details .getExternalTransactionToken ()).thenReturn (externalTransactionToken );
264
+ when (details .getOriginalExternalTransactionId ()).thenReturn (originalTransactionId );
265
+ when (details .getProducts ()).thenReturn (Collections .emptyList ());
266
+ billingCaptor .getValue ().userSelectedAlternativeBilling (details );
267
+
268
+ verify (mockMethodChannel , times (1 ))
269
+ .invokeMethod (USER_SELECTED_ALTERNATIVE_BILLING , fromUserChoiceDetails (details ));
270
+ }
271
+
272
+ @ Test
273
+ public void userChoiceBillingOnSecondConnection () {
274
+ // First connection.
275
+ ArgumentCaptor <BillingClientStateListener > captor1 =
276
+ mockStartConnection (BillingChoiceMode .PLAY_BILLING_ONLY );
277
+ verify (result , never ()).success (any ());
278
+ verify (factory , times (1 ))
279
+ .createBillingClient (context , mockMethodChannel , BillingChoiceMode .PLAY_BILLING_ONLY , null );
280
+
281
+ BillingResult billingResult1 =
282
+ BillingResult .newBuilder ()
283
+ .setResponseCode (100 )
284
+ .setDebugMessage ("dummy debug message" )
285
+ .build ();
286
+ final BillingClientStateListener stateListener = captor1 .getValue ();
287
+ stateListener .onBillingSetupFinished (billingResult1 );
288
+ verify (result , times (1 )).success (fromBillingResult (billingResult1 ));
289
+ Mockito .reset (result , mockMethodChannel , mockBillingClient );
290
+
291
+ // Disconnect
292
+ MethodCall disconnectCall = new MethodCall (END_CONNECTION , null );
293
+ methodChannelHandler .onMethodCall (disconnectCall , result );
294
+
295
+ // Verify that the client is disconnected and that the OnDisconnect callback has
296
+ // been triggered
297
+ verify (result , times (1 )).success (any ());
298
+ verify (mockBillingClient , times (1 )).endConnection ();
299
+ stateListener .onBillingServiceDisconnected ();
300
+ Map <String , Integer > expectedInvocation = new HashMap <>();
301
+ expectedInvocation .put ("handle" , DEFAULT_HANDLE );
302
+ verify (mockMethodChannel , times (1 )).invokeMethod (ON_DISCONNECT , expectedInvocation );
303
+ Mockito .reset (result , mockMethodChannel , mockBillingClient );
304
+
305
+ // Second connection.
306
+ ArgumentCaptor <BillingClientStateListener > captor2 =
307
+ mockStartConnection (BillingChoiceMode .USER_CHOICE_BILLING );
308
+ ArgumentCaptor <UserChoiceBillingListener > billingCaptor =
309
+ ArgumentCaptor .forClass (UserChoiceBillingListener .class );
310
+ verify (result , never ()).success (any ());
311
+ verify (factory , times (1 ))
312
+ .createBillingClient (
313
+ any (Context .class ),
314
+ any (MethodChannel .class ),
315
+ eq (BillingChoiceMode .USER_CHOICE_BILLING ),
316
+ billingCaptor .capture ());
317
+
318
+ BillingResult billingResult2 =
319
+ BillingResult .newBuilder ()
320
+ .setResponseCode (100 )
321
+ .setDebugMessage ("dummy debug message" )
322
+ .build ();
323
+ captor2 .getValue ().onBillingSetupFinished (billingResult2 );
324
+
325
+ verify (result , times (1 )).success (fromBillingResult (billingResult2 ));
326
+ UserChoiceDetails details = mock (UserChoiceDetails .class );
327
+ final String externalTransactionToken = "someLongTokenId1234" ;
328
+ final String originalTransactionId = "originalTransactionId123456" ;
329
+ when (details .getExternalTransactionToken ()).thenReturn (externalTransactionToken );
330
+ when (details .getOriginalExternalTransactionId ()).thenReturn (originalTransactionId );
331
+ when (details .getProducts ()).thenReturn (Collections .emptyList ());
332
+ billingCaptor .getValue ().userSelectedAlternativeBilling (details );
333
+
334
+ verify (mockMethodChannel , times (1 ))
335
+ .invokeMethod (USER_SELECTED_ALTERNATIVE_BILLING , fromUserChoiceDetails (details ));
336
+ }
337
+
224
338
@ Test
225
339
public void startConnection_multipleCalls () {
226
340
Map <String , Object > arguments = new HashMap <>();
@@ -1071,7 +1185,7 @@ private ArgumentCaptor<BillingClientStateListener> mockStartConnection() {
1071
1185
*/
1072
1186
private ArgumentCaptor <BillingClientStateListener > mockStartConnection (int billingChoiceMode ) {
1073
1187
Map <String , Object > arguments = new HashMap <>();
1074
- arguments .put (MethodArgs .HANDLE , 1 );
1188
+ arguments .put (MethodArgs .HANDLE , DEFAULT_HANDLE );
1075
1189
arguments .put (MethodArgs .BILLING_CHOICE_MODE , billingChoiceMode );
1076
1190
MethodCall call = new MethodCall (START_CONNECTION , arguments );
1077
1191
ArgumentCaptor <BillingClientStateListener > captor =
0 commit comments