expo-web-browser 10.2.1 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/android/build.gradle +3 -2
  3. package/android/src/main/java/expo/modules/webbrowser/CustomTabsActivitiesHelper.kt +123 -0
  4. package/android/src/main/java/expo/modules/webbrowser/CustomTabsConnectionHelper.kt +97 -0
  5. package/android/src/main/java/expo/modules/webbrowser/DeferredClientActionsQueue.kt +45 -0
  6. package/android/src/main/java/expo/modules/webbrowser/WebBrowserExceptions.kt +13 -0
  7. package/android/src/main/java/expo/modules/webbrowser/WebBrowserModule.kt +164 -0
  8. package/android/src/main/java/expo/modules/webbrowser/WebBrowserOptions.kt +15 -0
  9. package/build/ExpoWebBrowser.web.js +5 -5
  10. package/build/ExpoWebBrowser.web.js.map +1 -1
  11. package/build/WebBrowser.d.ts +6 -6
  12. package/build/WebBrowser.d.ts.map +1 -1
  13. package/build/WebBrowser.js +25 -16
  14. package/build/WebBrowser.js.map +1 -1
  15. package/build/WebBrowser.types.d.ts +3 -3
  16. package/build/WebBrowser.types.js.map +1 -1
  17. package/expo-module.config.json +3 -0
  18. package/ios/ExpoWebBrowser.podspec +1 -1
  19. package/ios/WebAuthSession.swift +2 -2
  20. package/ios/WebBrowserModule.swift +9 -9
  21. package/package.json +3 -3
  22. package/src/ExpoWebBrowser.web.ts +6 -6
  23. package/src/WebBrowser.ts +38 -19
  24. package/src/WebBrowser.types.ts +3 -3
  25. package/tsconfig.json +1 -1
  26. package/android/src/main/java/expo/modules/webbrowser/CustomTabsActivitiesHelper.java +0 -33
  27. package/android/src/main/java/expo/modules/webbrowser/CustomTabsConnectionHelper.java +0 -13
  28. package/android/src/main/java/expo/modules/webbrowser/DeferredClientActionsQueue.java +0 -50
  29. package/android/src/main/java/expo/modules/webbrowser/InternalCustomTabsActivitiesHelper.java +0 -127
  30. package/android/src/main/java/expo/modules/webbrowser/InternalCustomTabsConnectionHelper.java +0 -126
  31. package/android/src/main/java/expo/modules/webbrowser/WebBrowserModule.java +0 -218
  32. package/android/src/main/java/expo/modules/webbrowser/WebBrowserPackage.java +0 -27
  33. package/android/src/main/java/expo/modules/webbrowser/error/NoPreferredPackageFound.java +0 -15
  34. package/android/src/main/java/expo/modules/webbrowser/error/PackageManagerNotFoundException.java +0 -10
package/src/WebBrowser.ts CHANGED
@@ -1,5 +1,12 @@
1
1
  import { UnavailabilityError } from 'expo-modules-core';
2
- import { AppState, AppStateStatus, Linking, Platform } from 'react-native';
2
+ import {
3
+ AppState,
4
+ AppStateStatus,
5
+ Linking,
6
+ Platform,
7
+ EmitterSubscription,
8
+ processColor,
9
+ } from 'react-native';
3
10
 
4
11
  import ExponentWebBrowser from './ExpoWebBrowser';
5
12
  import {
@@ -177,7 +184,7 @@ export async function openBrowserAsync(
177
184
 
178
185
  let result: WebBrowserResult;
179
186
  try {
180
- result = await ExponentWebBrowser.openBrowserAsync(url, browserParams);
187
+ result = await ExponentWebBrowser.openBrowserAsync(url, _processOptions(browserParams));
181
188
  } finally {
182
189
  // WebBrowser session complete, unset lock
183
190
  browserLocked = false;
@@ -203,9 +210,8 @@ export function dismissBrowser(): void {
203
210
  // @needsAudit
204
211
  /**
205
212
  * # On iOS:
206
- * Opens the url with Safari in a modal using `SFAuthenticationSession` on iOS 11 and greater,
207
- * and falling back on a `SFSafariViewController`. The user will be asked whether to allow the app
208
- * to authenticate using the given url.
213
+ * Opens the url with Safari in a modal using `ASWebAuthenticationSession`. The user will be asked
214
+ * whether to allow the app to authenticate using the given url.
209
215
  *
210
216
  * # On Android:
211
217
  * This will be done using a "custom Chrome tabs" browser, [AppState](../react-native/appstate/),
@@ -220,7 +226,7 @@ export function dismissBrowser(): void {
220
226
  *
221
227
  * How this works on web:
222
228
  * - A crypto state will be created for verifying the redirect.
223
- * - This means you need to run with `expo start:web --https`
229
+ * - This means you need to run with `npx expo start --https`
224
230
  * - The state will be added to the window's `localstorage`. This ensures that auth cannot complete
225
231
  * unless it's done from a page running with the same origin as it was started.
226
232
  * Ex: if `openAuthSessionAsync` is invoked on `https://localhost:19006`, then `maybeCompleteAuthSession`
@@ -234,7 +240,8 @@ export function dismissBrowser(): void {
234
240
  * after a user interaction. If the event is blocked, an error with code [`ERR_WEB_BROWSER_BLOCKED`](#errwebbrowserblocked) will be thrown.
235
241
  *
236
242
  * @param url The url to open in the web browser. This should be a login page.
237
- * @param redirectUrl _Optional_ - The url to deep link back into your app. By default, this will be [`Constants.linkingUrl`](./constants/#expoconstantslinkinguri).
243
+ * @param redirectUrl _Optional_ - The url to deep link back into your app.
244
+ * On web, this defaults to the output of [`Linking.createURL("")`](./linking/#linkingcreateurlpath-namedparameters).
238
245
  * @param options _Optional_ - An object extending the [`WebBrowserOpenOptions`](#webbrowseropenoptions).
239
246
  * If there is no native AuthSession implementation available (which is the case on Android)
240
247
  * these params will be used in the browser polyfill. If there is a native AuthSession implementation,
@@ -248,7 +255,7 @@ export function dismissBrowser(): void {
248
255
  */
249
256
  export async function openAuthSessionAsync(
250
257
  url: string,
251
- redirectUrl: string,
258
+ redirectUrl?: string | null,
252
259
  options: AuthSessionOpenOptions = {}
253
260
  ): Promise<WebBrowserAuthSessionResult> {
254
261
  if (_authSessionIsNativelySupported()) {
@@ -256,7 +263,7 @@ export async function openAuthSessionAsync(
256
263
  throw new UnavailabilityError('WebBrowser', 'openAuthSessionAsync');
257
264
  }
258
265
  if (['ios', 'web'].includes(Platform.OS)) {
259
- return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl, options);
266
+ return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl, _processOptions(options));
260
267
  }
261
268
  return ExponentWebBrowser.openAuthSessionAsync(url, redirectUrl);
262
269
  } else {
@@ -317,6 +324,15 @@ export function maybeCompleteAuthSession(
317
324
  return { type: 'failed', message: 'Not supported on this platform' };
318
325
  }
319
326
 
327
+ function _processOptions(options: WebBrowserOpenOptions) {
328
+ return {
329
+ ...options,
330
+ controlsColor: processColor(options.controlsColor),
331
+ toolbarColor: processColor(options.toolbarColor),
332
+ secondaryToolbarColor: processColor(options.secondaryToolbarColor),
333
+ };
334
+ }
335
+
320
336
  /* iOS <= 10 and Android polyfill for SFAuthenticationSession flow */
321
337
 
322
338
  function _authSessionIsNativelySupported(): boolean {
@@ -330,7 +346,7 @@ function _authSessionIsNativelySupported(): boolean {
330
346
  return versionNumber >= 11;
331
347
  }
332
348
 
333
- let _redirectHandler: ((event: RedirectEvent) => void) | null = null;
349
+ let _redirectSubscription: EmitterSubscription | null = null;
334
350
 
335
351
  /*
336
352
  * openBrowserAsync on Android doesn't wait until closed, so we need to polyfill
@@ -389,10 +405,10 @@ async function _openBrowserAndWaitAndroidAsync(
389
405
 
390
406
  async function _openAuthSessionPolyfillAsync(
391
407
  startUrl: string,
392
- returnUrl: string,
408
+ returnUrl: string | null | undefined,
393
409
  browserParams: WebBrowserOpenOptions = {}
394
410
  ): Promise<WebBrowserAuthSessionResult> {
395
- if (_redirectHandler) {
411
+ if (_redirectSubscription) {
396
412
  throw new Error(
397
413
  `The WebBrowser's auth session is in an invalid state with a redirect handler set when it should not be`
398
414
  );
@@ -426,24 +442,27 @@ async function _openAuthSessionPolyfillAsync(
426
442
  }
427
443
 
428
444
  function _stopWaitingForRedirect() {
429
- if (!_redirectHandler) {
445
+ if (!_redirectSubscription) {
430
446
  throw new Error(
431
447
  `The WebBrowser auth session is in an invalid state with no redirect handler when one should be set`
432
448
  );
433
449
  }
434
450
 
435
- Linking.removeEventListener('url', _redirectHandler);
436
- _redirectHandler = null;
451
+ _redirectSubscription.remove();
452
+ _redirectSubscription = null;
437
453
  }
438
454
 
439
- function _waitForRedirectAsync(returnUrl: string): Promise<WebBrowserRedirectResult> {
455
+ function _waitForRedirectAsync(
456
+ returnUrl: string | null | undefined
457
+ ): Promise<WebBrowserRedirectResult> {
458
+ // Note that this Promise never resolves when `returnUrl` is nullish
440
459
  return new Promise((resolve) => {
441
- _redirectHandler = (event: RedirectEvent) => {
442
- if (event.url.startsWith(returnUrl)) {
460
+ const redirectHandler = (event: RedirectEvent) => {
461
+ if (returnUrl && event.url.startsWith(returnUrl)) {
443
462
  resolve({ url: event.url, type: 'success' });
444
463
  }
445
464
  };
446
465
 
447
- Linking.addEventListener('url', _redirectHandler);
466
+ _redirectSubscription = Linking.addEventListener('url', redirectHandler);
448
467
  });
449
468
  }
@@ -8,7 +8,7 @@ export type WebBrowserWindowFeatures = Record<string, number | boolean | string>
8
8
  // @needsAudit
9
9
  export type WebBrowserOpenOptions = {
10
10
  /**
11
- * Color of the toolbar in either `#AARRGGBB` or `#RRGGBB` format.
11
+ * Color of the toolbar. Supports React Native [color formats](https://reactnative.dev/docs/colors).
12
12
  */
13
13
  toolbarColor?: string;
14
14
  /**
@@ -22,7 +22,7 @@ export type WebBrowserOpenOptions = {
22
22
  */
23
23
  enableBarCollapsing?: boolean;
24
24
  /**
25
- * Color of the secondary toolbar in either `#AARRGGBB` or `#RRGGBB` format.
25
+ * Color of the secondary toolbar. Supports React Native [color formats](https://reactnative.dev/docs/colors).
26
26
  * @platform android
27
27
  */
28
28
  secondaryToolbarColor?: string;
@@ -51,7 +51,7 @@ export type WebBrowserOpenOptions = {
51
51
  */
52
52
  createTask?: boolean;
53
53
  /**
54
- * Tint color for controls in SKSafariViewController in `#AARRGGBB` or `#RRGGBB` format.
54
+ * Tint color for controls in SKSafariViewController. Supports React Native [color formats](https://reactnative.dev/docs/colors).
55
55
  * @platform ios
56
56
  */
57
57
  controlsColor?: string;
package/tsconfig.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "outDir": "./build"
6
6
  },
7
7
  "include": ["./src"],
8
- "exclude": ["**/__mocks__/*", "**/__tests__/*"]
8
+ "exclude": ["**/__mocks__/*", "**/__tests__/*", "**/__stories__/*"]
9
9
  }
@@ -1,33 +0,0 @@
1
- package expo.modules.webbrowser;
2
-
3
- import android.content.Intent;
4
- import android.content.pm.ResolveInfo;
5
-
6
- import expo.modules.core.errors.CurrentActivityNotFoundException;
7
- import expo.modules.core.interfaces.InternalModule;
8
-
9
- import java.util.ArrayList;
10
- import java.util.List;
11
-
12
- import androidx.annotation.NonNull;
13
- import androidx.annotation.Nullable;
14
- import expo.modules.webbrowser.error.PackageManagerNotFoundException;
15
-
16
- public interface CustomTabsActivitiesHelper extends InternalModule {
17
-
18
- @NonNull
19
- ArrayList<String> getCustomTabsResolvingActivities() throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
20
-
21
- @NonNull
22
- ArrayList<String> getCustomTabsResolvingServices() throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
23
-
24
- @Nullable
25
- String getPreferredCustomTabsResolvingActivity(@Nullable List<String> packages) throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
26
-
27
- @Nullable
28
- String getDefaultCustomTabsResolvingActivity() throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
29
-
30
- void startCustomTabs(Intent intent) throws CurrentActivityNotFoundException;
31
-
32
- boolean canResolveIntent(Intent intent) throws PackageManagerNotFoundException, CurrentActivityNotFoundException;
33
- }
@@ -1,13 +0,0 @@
1
- package expo.modules.webbrowser;
2
-
3
- import android.net.Uri;
4
-
5
- import expo.modules.core.interfaces.InternalModule;
6
-
7
- public interface CustomTabsConnectionHelper extends InternalModule {
8
- void warmUp(String packageName);
9
-
10
- void mayInitWithUrl(String packageName, Uri uri);
11
-
12
- boolean coolDown(String packageName);
13
- }
@@ -1,50 +0,0 @@
1
- package expo.modules.webbrowser;
2
-
3
- import expo.modules.core.interfaces.Consumer;
4
-
5
- import java.util.LinkedList;
6
- import java.util.Queue;
7
-
8
-
9
- public class DeferredClientActionsQueue<T> {
10
-
11
- private Queue<Consumer<T>> actions = new LinkedList<>();
12
- private T client;
13
-
14
- public void executeOrQueueAction(Consumer<T> action) {
15
- if (client != null) {
16
- action.apply(client);
17
- } else {
18
- addActionToQueue(action);
19
- }
20
- }
21
-
22
- public void setClient(T client) {
23
- this.client = client;
24
- executeQueuedActions();
25
- }
26
-
27
- public void clear() {
28
- this.client = null;
29
- this.actions.clear();
30
- }
31
-
32
- public boolean hasClient() {
33
- return client != null;
34
- }
35
-
36
- private void executeQueuedActions() {
37
- if (client != null) {
38
- Consumer<T> action = actions.poll();
39
- while (action != null) {
40
- action.apply(client);
41
- action = actions.poll();
42
- }
43
- }
44
- }
45
-
46
- private void addActionToQueue(Consumer<T> consumer) {
47
- actions.add(consumer);
48
- }
49
-
50
- }
@@ -1,127 +0,0 @@
1
- package expo.modules.webbrowser;
2
-
3
- import android.app.Activity;
4
- import android.content.Intent;
5
- import android.content.pm.PackageManager;
6
- import android.content.pm.ResolveInfo;
7
- import android.net.Uri;
8
-
9
- import expo.modules.core.ModuleRegistry;
10
- import expo.modules.core.errors.CurrentActivityNotFoundException;
11
- import expo.modules.core.interfaces.ActivityProvider;
12
- import expo.modules.core.interfaces.Function;
13
- import expo.modules.core.interfaces.InternalModule;
14
-
15
- import java.util.ArrayList;
16
- import java.util.Collection;
17
- import java.util.Collections;
18
- import java.util.LinkedHashSet;
19
- import java.util.List;
20
-
21
- import androidx.annotation.NonNull;
22
- import androidx.annotation.Nullable;
23
- import androidx.browser.customtabs.CustomTabsClient;
24
- import androidx.browser.customtabs.CustomTabsIntent;
25
- import expo.modules.webbrowser.error.PackageManagerNotFoundException;
26
-
27
- import static androidx.browser.customtabs.CustomTabsService.ACTION_CUSTOM_TABS_CONNECTION;
28
-
29
- class InternalCustomTabsActivitiesHelper implements CustomTabsActivitiesHelper {
30
-
31
-
32
- private final static String DUMMY_URL = "https://expo.io";
33
-
34
- private ModuleRegistry mModuleRegistry;
35
-
36
- @NonNull
37
- public static <T, R> ArrayList<R> mapCollectionToDistinctArrayList(Collection<? extends T> toMap, Function<T, R> mapper) {
38
- LinkedHashSet<R> resultSet = new LinkedHashSet<>();
39
- for (T element : toMap) {
40
- resultSet.add(mapper.apply(element));
41
- }
42
- return new ArrayList<>(resultSet);
43
- }
44
-
45
- @Override
46
- public void onCreate(ModuleRegistry moduleRegistry) {
47
- this.mModuleRegistry = moduleRegistry;
48
- }
49
-
50
- @Override
51
- @NonNull
52
- public ArrayList<String> getCustomTabsResolvingActivities() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
53
- return mapCollectionToDistinctArrayList(getResolvingActivities(createDefaultCustomTabsIntent()), resolveInfo -> resolveInfo.activityInfo.packageName);
54
- }
55
-
56
- @Override
57
- @NonNull
58
- public ArrayList<String> getCustomTabsResolvingServices() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
59
- return mapCollectionToDistinctArrayList(getPackageManager().queryIntentServices(createDefaultCustomTabsServiceIntent(), 0), resolveInfo -> resolveInfo.serviceInfo.packageName);
60
- }
61
-
62
- @Override
63
- @Nullable
64
- public String getPreferredCustomTabsResolvingActivity(@Nullable List<String> packages) throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
65
- if (packages == null) packages = getCustomTabsResolvingActivities();
66
- return CustomTabsClient.getPackageName(getCurrentActivity(), packages);
67
- }
68
-
69
- @Override
70
- @Nullable
71
- public String getDefaultCustomTabsResolvingActivity() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
72
- ResolveInfo info = getPackageManager().resolveActivity(createDefaultCustomTabsIntent(), 0);
73
- return info == null ? null : info.activityInfo.packageName;
74
- }
75
-
76
- @Override
77
- public boolean canResolveIntent(@NonNull Intent intent) throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
78
- return getResolvingActivities(intent).size() > 0;
79
- }
80
-
81
- public void startCustomTabs(Intent intent) throws CurrentActivityNotFoundException {
82
- getCurrentActivity().startActivity(intent);
83
- }
84
-
85
- private List<ResolveInfo> getResolvingActivities(@NonNull Intent intent) throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
86
- return getPackageManager().queryIntentActivities(intent, 0);
87
- }
88
-
89
- private PackageManager getPackageManager() throws PackageManagerNotFoundException, CurrentActivityNotFoundException {
90
- PackageManager pm = getCurrentActivity().getPackageManager();
91
- if (pm == null) throw new PackageManagerNotFoundException();
92
- else return pm;
93
- }
94
-
95
- private Activity getCurrentActivity() throws CurrentActivityNotFoundException {
96
- ActivityProvider activityProvider = mModuleRegistry.getModule(ActivityProvider.class);
97
- if (activityProvider == null || activityProvider.getCurrentActivity() == null) {
98
- throw new CurrentActivityNotFoundException();
99
- }
100
- return activityProvider.getCurrentActivity();
101
- }
102
-
103
- private Intent createDefaultCustomTabsIntent() {
104
- CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
105
- CustomTabsIntent customTabsIntent = builder.build();
106
-
107
- Intent intent = customTabsIntent.intent;
108
- intent.setData(Uri.parse(DUMMY_URL));
109
- return intent;
110
- }
111
-
112
- private Intent createDefaultCustomTabsServiceIntent() {
113
- Intent serviceIntent = new Intent();
114
- serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
115
- return serviceIntent;
116
- }
117
-
118
- @Override
119
- public void onDestroy() {
120
-
121
- }
122
-
123
- @Override
124
- public List<? extends Class> getExportedInterfaces() {
125
- return Collections.singletonList(CustomTabsActivitiesHelper.class);
126
- }
127
- }
@@ -1,126 +0,0 @@
1
- package expo.modules.webbrowser;
2
-
3
- import android.content.ComponentName;
4
- import android.content.Context;
5
- import android.net.Uri;
6
- import androidx.browser.customtabs.CustomTabsClient;
7
- import androidx.browser.customtabs.CustomTabsServiceConnection;
8
- import androidx.browser.customtabs.CustomTabsSession;
9
-
10
- import expo.modules.core.interfaces.InternalModule;
11
- import expo.modules.core.interfaces.LifecycleEventListener;
12
-
13
- import java.util.Collections;
14
- import java.util.List;
15
-
16
- public class InternalCustomTabsConnectionHelper extends CustomTabsServiceConnection implements LifecycleEventListener, CustomTabsConnectionHelper {
17
-
18
- private Context mContext;
19
- private String mPackageName;
20
- private DeferredClientActionsQueue<CustomTabsClient> clientActions = new DeferredClientActionsQueue<>();
21
- private DeferredClientActionsQueue<CustomTabsSession> sessionActions = new DeferredClientActionsQueue<>();
22
-
23
- InternalCustomTabsConnectionHelper(Context context) {
24
- this.mContext = context;
25
- }
26
-
27
- @Override
28
- public void warmUp(String packageName) {
29
- clientActions.executeOrQueueAction(client -> client.warmup(0));
30
- ensureConnection(packageName);
31
- }
32
-
33
- @Override
34
- public void mayInitWithUrl(String packageName, Uri uri) {
35
- sessionActions.executeOrQueueAction(session -> session.mayLaunchUrl(uri, null, null));
36
- ensureConnection(packageName);
37
- ensureSession();
38
- }
39
-
40
- private void ensureSession() {
41
- if (!sessionActions.hasClient()) {
42
- clientActions.executeOrQueueAction(
43
- client ->
44
- sessionActions.setClient(client.newSession(null)));
45
- }
46
- }
47
-
48
- @Override
49
- public boolean coolDown(String packageName) {
50
- if (packageName.equals(this.mPackageName)) {
51
- unbindService();
52
- return true;
53
- }
54
- return false;
55
- }
56
-
57
- private void ensureConnection(String packageName) {
58
- if (this.mPackageName != null && !this.mPackageName.equals(packageName)) {
59
- clearConnection();
60
- }
61
- if (!connectionStarted(packageName)) {
62
- CustomTabsClient.bindCustomTabsService(getContext(), packageName, this);
63
- this.mPackageName = packageName;
64
- }
65
- }
66
-
67
- private boolean connectionStarted(String packageName) {
68
- return packageName.equals(this.mPackageName);
69
- }
70
-
71
- @Override
72
- public void onBindingDied(ComponentName componentName) {
73
- if (componentName.getPackageName().equals(this.mPackageName)) {
74
- clearConnection();
75
- }
76
- }
77
-
78
- @Override
79
- public void onCustomTabsServiceConnected(ComponentName componentName, CustomTabsClient client) {
80
- if (componentName.getPackageName().equals(mPackageName)) {
81
- clientActions.setClient(client);
82
- }
83
- }
84
-
85
- @Override
86
- public void onServiceDisconnected(ComponentName componentName) {
87
- if (componentName.getPackageName().equals(this.mPackageName)) {
88
- clearConnection();
89
- }
90
- }
91
-
92
- @Override
93
- public void onHostResume() {
94
- // do nothing
95
- }
96
-
97
- @Override
98
- public void onHostPause() {
99
- // do nothing
100
- }
101
-
102
- @Override
103
- public void onHostDestroy() {
104
- unbindService();
105
- }
106
-
107
- private void unbindService() {
108
- getContext().unbindService(this);
109
- clearConnection();
110
- }
111
-
112
- private void clearConnection() {
113
- this.mPackageName = null;
114
- clientActions.clear();
115
- sessionActions.clear();
116
- }
117
-
118
- private Context getContext() {
119
- return mContext;
120
- }
121
-
122
- @Override
123
- public List<? extends Class> getExportedInterfaces() {
124
- return Collections.singletonList(CustomTabsConnectionHelper.class);
125
- }
126
- }