@iternio/react-native-auto-play 0.6.1 → 0.8.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 (211) hide show
  1. package/README.md +17 -4
  2. package/android/build.gradle +4 -2
  3. package/android/src/automotive/AndroidManifest-nonnav.xml +0 -2
  4. package/android/src/automotive/AndroidManifest.xml +0 -2
  5. package/android/src/main/AndroidManifest-nonnav.xml +0 -2
  6. package/android/src/main/AndroidManifest.xml +0 -2
  7. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AndroidAutoService.kt +3 -27
  8. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/AutoPlayError.kt +4 -0
  9. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlayTiming.kt +122 -0
  10. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridSignInTemplate.kt +23 -0
  11. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/SignInWithGoogleActivity.kt +79 -27
  12. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/Parser.kt +2 -2
  13. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/template/SignInTemplate.kt +35 -21
  14. package/installTimers.ts +3 -0
  15. package/installTimers.web.ts +2 -0
  16. package/ios/hybrid/HybridAutoPlayTiming.swift +123 -0
  17. package/lib/components/SafeAreaView.js +1 -1
  18. package/lib/hybrid/HybridAutoPlayTiming.d.ts +2 -0
  19. package/lib/hybrid/HybridAutoPlayTiming.js +2 -0
  20. package/lib/hybrid/HybridVoice.js +2 -2
  21. package/lib/index.js +0 -2
  22. package/lib/index.web.d.ts +4 -2
  23. package/lib/installTimers.d.ts +1 -0
  24. package/lib/installTimers.js +8 -0
  25. package/lib/installTimers.web.d.ts +1 -0
  26. package/lib/installTimers.web.js +2 -0
  27. package/lib/scenes/CarPlayDashboardScene.d.ts +3 -3
  28. package/lib/specs/AutoPlayTiming.nitro.d.ts +27 -0
  29. package/lib/specs/AutoPlayTiming.nitro.js +1 -0
  30. package/lib/specs/SignInTemplate.nitro.d.ts +1 -0
  31. package/lib/templates/SignInTemplate.d.ts +5 -0
  32. package/lib/templates/SignInTemplate.js +7 -0
  33. package/lib/types/Telemetry.d.ts +1 -1
  34. package/lib/utils/AutoPlayTimers.d.ts +21 -0
  35. package/lib/utils/AutoPlayTimers.js +45 -0
  36. package/lib/utils/NitroImage.d.ts +5 -2
  37. package/lib/utils/NitroImage.js +1 -1
  38. package/lib-cjs/components/SafeAreaView.js +1 -1
  39. package/lib-cjs/hybrid/HybridVoice.js +2 -2
  40. package/lib-cjs/index.js +0 -5
  41. package/lib-cjs/templates/SignInTemplate.js +7 -0
  42. package/lib-cjs/utils/NitroImage.js +1 -1
  43. package/nitro.json +10 -0
  44. package/nitrogen/generated/android/ReactNativeAutoPlay+autolinking.cmake +2 -0
  45. package/nitrogen/generated/android/ReactNativeAutoPlayOnLoad.cpp +16 -0
  46. package/nitrogen/generated/android/c++/JActiveCarUxRestrictions.hpp +1 -1
  47. package/nitrogen/generated/android/c++/JAlertActionStyle.hpp +1 -1
  48. package/nitrogen/generated/android/c++/JAlertDismissalReason.hpp +1 -1
  49. package/nitrogen/generated/android/c++/JAppFocusState.hpp +1 -1
  50. package/nitrogen/generated/android/c++/JAssetImage.hpp +18 -18
  51. package/nitrogen/generated/android/c++/JAutoText.hpp +1 -1
  52. package/nitrogen/generated/android/c++/JBooleanTelemetryItem.hpp +1 -1
  53. package/nitrogen/generated/android/c++/JCarUxRestrictions.hpp +1 -1
  54. package/nitrogen/generated/android/c++/JChargingConnector.hpp +1 -1
  55. package/nitrogen/generated/android/c++/JClusterEventName.hpp +1 -1
  56. package/nitrogen/generated/android/c++/JColorScheme.hpp +1 -1
  57. package/nitrogen/generated/android/c++/JDistance.hpp +1 -1
  58. package/nitrogen/generated/android/c++/JDistanceUnits.hpp +1 -1
  59. package/nitrogen/generated/android/c++/JDurationWithTimeZone.hpp +1 -1
  60. package/nitrogen/generated/android/c++/JEventName.hpp +1 -1
  61. package/nitrogen/generated/android/c++/JForkType.hpp +1 -1
  62. package/nitrogen/generated/android/c++/JGlyphImage.hpp +1 -1
  63. package/nitrogen/generated/android/c++/JGoogleSignIn.hpp +1 -1
  64. package/nitrogen/generated/android/c++/JGoogleSignInAccount.hpp +1 -1
  65. package/nitrogen/generated/android/c++/JGridImageSize.hpp +1 -1
  66. package/nitrogen/generated/android/c++/JGridTemplateConfig.hpp +1 -1
  67. package/nitrogen/generated/android/c++/JHybridAutoPlayTimingSpec.cpp +59 -0
  68. package/nitrogen/generated/android/c++/JHybridAutoPlayTimingSpec.hpp +64 -0
  69. package/nitrogen/generated/android/c++/JHybridSignInTemplateSpec.cpp +5 -0
  70. package/nitrogen/generated/android/c++/JHybridSignInTemplateSpec.hpp +1 -0
  71. package/nitrogen/generated/android/c++/JImageLane.hpp +1 -1
  72. package/nitrogen/generated/android/c++/JInformationTemplateConfig.hpp +1 -1
  73. package/nitrogen/generated/android/c++/JInputSignIn.hpp +1 -1
  74. package/nitrogen/generated/android/c++/JKeepType.hpp +1 -1
  75. package/nitrogen/generated/android/c++/JKeyboardType.hpp +1 -1
  76. package/nitrogen/generated/android/c++/JLaneGuidance.hpp +1 -1
  77. package/nitrogen/generated/android/c++/JListImageType.hpp +1 -1
  78. package/nitrogen/generated/android/c++/JListTemplateConfig.hpp +1 -1
  79. package/nitrogen/generated/android/c++/JLocation.hpp +1 -1
  80. package/nitrogen/generated/android/c++/JManeuverState.hpp +1 -1
  81. package/nitrogen/generated/android/c++/JManeuverType.hpp +1 -1
  82. package/nitrogen/generated/android/c++/JMapTemplateConfig.hpp +1 -1
  83. package/nitrogen/generated/android/c++/JMessageTemplateConfig.hpp +1 -1
  84. package/nitrogen/generated/android/c++/JNavigationAlertAction.hpp +1 -1
  85. package/nitrogen/generated/android/c++/JNitroAction.hpp +1 -1
  86. package/nitrogen/generated/android/c++/JNitroActionType.hpp +1 -1
  87. package/nitrogen/generated/android/c++/JNitroAlignment.hpp +1 -1
  88. package/nitrogen/generated/android/c++/JNitroAttributedString.hpp +1 -1
  89. package/nitrogen/generated/android/c++/JNitroAttributedStringImage.hpp +1 -1
  90. package/nitrogen/generated/android/c++/JNitroBaseMapTemplateConfig.hpp +1 -1
  91. package/nitrogen/generated/android/c++/JNitroButtonStyle.hpp +1 -1
  92. package/nitrogen/generated/android/c++/JNitroChargerLocation.hpp +1 -1
  93. package/nitrogen/generated/android/c++/JNitroChargerOutlet.hpp +1 -1
  94. package/nitrogen/generated/android/c++/JNitroColor.hpp +1 -1
  95. package/nitrogen/generated/android/c++/JNitroGridButton.hpp +1 -1
  96. package/nitrogen/generated/android/c++/JNitroLoadingManeuver.hpp +1 -1
  97. package/nitrogen/generated/android/c++/JNitroMapButton.hpp +1 -1
  98. package/nitrogen/generated/android/c++/JNitroMapButtonType.hpp +1 -1
  99. package/nitrogen/generated/android/c++/JNitroMessageManeuver.hpp +1 -1
  100. package/nitrogen/generated/android/c++/JNitroNavigationAlert.hpp +1 -1
  101. package/nitrogen/generated/android/c++/JNitroOptionsPanelChargerSection.hpp +1 -1
  102. package/nitrogen/generated/android/c++/JNitroOptionsPanelConfig.hpp +1 -1
  103. package/nitrogen/generated/android/c++/JNitroOptionsPanelGridSection.hpp +1 -1
  104. package/nitrogen/generated/android/c++/JNitroRoutingManeuver.hpp +1 -1
  105. package/nitrogen/generated/android/c++/JNitroRow.hpp +1 -1
  106. package/nitrogen/generated/android/c++/JNitroSection.hpp +1 -1
  107. package/nitrogen/generated/android/c++/JNitroSectionType.hpp +1 -1
  108. package/nitrogen/generated/android/c++/JNumericTelemetryItem.hpp +1 -1
  109. package/nitrogen/generated/android/c++/JOffRampType.hpp +1 -1
  110. package/nitrogen/generated/android/c++/JOnRampType.hpp +1 -1
  111. package/nitrogen/generated/android/c++/JPermissionRequestResult.hpp +1 -1
  112. package/nitrogen/generated/android/c++/JPinSignIn.hpp +1 -1
  113. package/nitrogen/generated/android/c++/JPoint.hpp +1 -1
  114. package/nitrogen/generated/android/c++/JPreferredImageLane.hpp +1 -1
  115. package/nitrogen/generated/android/c++/JQrSignIn.hpp +1 -1
  116. package/nitrogen/generated/android/c++/JRemoteImage.hpp +1 -1
  117. package/nitrogen/generated/android/c++/JRouteChoice.hpp +1 -1
  118. package/nitrogen/generated/android/c++/JSafeAreaInsets.hpp +1 -1
  119. package/nitrogen/generated/android/c++/JSearchTemplateConfig.hpp +1 -1
  120. package/nitrogen/generated/android/c++/JSignInMethods.hpp +1 -1
  121. package/nitrogen/generated/android/c++/JSignInTemplateConfig.hpp +1 -1
  122. package/nitrogen/generated/android/c++/JStringTelemetryItem.hpp +1 -1
  123. package/nitrogen/generated/android/c++/JTelemetry.hpp +1 -1
  124. package/nitrogen/generated/android/c++/JTextInputType.hpp +1 -1
  125. package/nitrogen/generated/android/c++/JTrafficSide.hpp +1 -1
  126. package/nitrogen/generated/android/c++/JTravelEstimates.hpp +1 -1
  127. package/nitrogen/generated/android/c++/JTripConfig.hpp +1 -1
  128. package/nitrogen/generated/android/c++/JTripPoint.hpp +1 -1
  129. package/nitrogen/generated/android/c++/JTripPreviewTextConfiguration.hpp +1 -1
  130. package/nitrogen/generated/android/c++/JTripSelectorCallback.hpp +1 -1
  131. package/nitrogen/generated/android/c++/JTripsConfig.hpp +1 -1
  132. package/nitrogen/generated/android/c++/JTurnType.hpp +1 -1
  133. package/nitrogen/generated/android/c++/JVehicleTelemetryItem.hpp +1 -1
  134. package/nitrogen/generated/android/c++/JVisibilityState.hpp +1 -1
  135. package/nitrogen/generated/android/c++/JVisibleTravelEstimate.hpp +1 -1
  136. package/nitrogen/generated/android/c++/JVoiceAudioEncoding.hpp +1 -1
  137. package/nitrogen/generated/android/c++/JVoiceInputChunk.hpp +1 -1
  138. package/nitrogen/generated/android/c++/JVoiceInputResult.hpp +1 -1
  139. package/nitrogen/generated/android/c++/JWaypointCoordinate.hpp +1 -1
  140. package/nitrogen/generated/android/c++/JWindowInformation.hpp +1 -1
  141. package/nitrogen/generated/android/c++/JZoomEvent.hpp +1 -1
  142. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/AssetImage.kt +15 -15
  143. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void.kt +0 -2
  144. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_ActiveCarUxRestrictions.kt +0 -2
  145. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_AlertDismissalReason.kt +0 -2
  146. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_AppFocusState.kt +0 -2
  147. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_ColorScheme.kt +0 -2
  148. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point.kt +0 -2
  149. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point_double.kt +0 -2
  150. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_Point_std__optional_Point_.kt +0 -2
  151. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_SafeAreaInsets.kt +0 -2
  152. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_VisibilityState.kt +0 -2
  153. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_VoiceInputChunk.kt +0 -2
  154. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_WindowInformation.kt +0 -2
  155. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_bool.kt +0 -2
  156. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_Location__std__optional_std__string_.kt +0 -2
  157. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_Telemetry_.kt +0 -2
  158. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_bool_.kt +0 -2
  159. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__optional_std__string__std__optional_GoogleSignInAccount_.kt +0 -2
  160. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string.kt +0 -2
  161. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_ColorScheme.kt +0 -2
  162. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_ZoomEvent.kt +0 -2
  163. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_bool.kt +0 -2
  164. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/Func_void_std__string_std__string.kt +0 -2
  165. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidAutoTelemetrySpec.kt +2 -0
  166. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidAutomotiveSpec.kt +2 -0
  167. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAndroidWindowInformationSpec.kt +2 -0
  168. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlaySpec.kt +2 -0
  169. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridAutoPlayTimingSpec.kt +65 -0
  170. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridClusterSpec.kt +2 -0
  171. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridGridTemplateSpec.kt +2 -0
  172. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridInformationTemplateSpec.kt +2 -0
  173. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridListTemplateSpec.kt +2 -0
  174. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMapTemplateSpec.kt +2 -0
  175. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridMessageTemplateSpec.kt +2 -0
  176. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridSearchTemplateSpec.kt +2 -0
  177. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridSignInTemplateSpec.kt +6 -0
  178. package/nitrogen/generated/android/kotlin/com/margelo/nitro/swe/iternio/reactnativeautoplay/HybridVoiceSpec.kt +2 -0
  179. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.cpp +17 -0
  180. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Bridge.hpp +35 -9
  181. package/nitrogen/generated/ios/ReactNativeAutoPlay-Swift-Cxx-Umbrella.hpp +5 -0
  182. package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.mm +8 -0
  183. package/nitrogen/generated/ios/ReactNativeAutoPlayAutolinking.swift +12 -0
  184. package/nitrogen/generated/ios/c++/HybridAutoPlayTimingSpecSwift.cpp +11 -0
  185. package/nitrogen/generated/ios/c++/HybridAutoPlayTimingSpecSwift.hpp +88 -0
  186. package/nitrogen/generated/ios/swift/AssetImage.swift +13 -13
  187. package/nitrogen/generated/ios/swift/HybridAutoPlayTimingSpec.swift +56 -0
  188. package/nitrogen/generated/ios/swift/HybridAutoPlayTimingSpec_cxx.swift +154 -0
  189. package/nitrogen/generated/shared/c++/AssetImage.hpp +18 -18
  190. package/nitrogen/generated/shared/c++/HybridAutoPlayTimingSpec.cpp +22 -0
  191. package/nitrogen/generated/shared/c++/HybridAutoPlayTimingSpec.hpp +63 -0
  192. package/nitrogen/generated/shared/c++/HybridSignInTemplateSpec.cpp +1 -0
  193. package/nitrogen/generated/shared/c++/HybridSignInTemplateSpec.hpp +1 -0
  194. package/package.json +6 -4
  195. package/src/components/SafeAreaView.tsx +1 -1
  196. package/src/hybrid/HybridAutoPlayTiming.ts +5 -0
  197. package/src/hybrid/HybridVoice.ts +2 -2
  198. package/src/index.ts +0 -3
  199. package/src/installTimers.ts +9 -0
  200. package/src/installTimers.web.ts +2 -0
  201. package/src/specs/AutoPlayTiming.nitro.ts +25 -0
  202. package/src/specs/SignInTemplate.nitro.ts +1 -0
  203. package/src/templates/SignInTemplate.ts +8 -0
  204. package/src/types/Telemetry.ts +1 -1
  205. package/src/utils/AutoPlayTimers.ts +60 -0
  206. package/src/utils/NitroImage.ts +13 -3
  207. package/android/src/main/java/com/margelo/nitro/swe/iternio/reactnativeautoplay/HeadlessTaskService.kt +0 -36
  208. package/lib/AutoPlayHeadlessJsTask.d.ts +0 -5
  209. package/lib/AutoPlayHeadlessJsTask.js +0 -14
  210. package/lib-cjs/AutoPlayHeadlessJsTask.js +0 -16
  211. package/src/AutoPlayHeadlessJsTask.ts +0 -22
package/README.md CHANGED
@@ -25,6 +25,7 @@
25
25
  ## Requirements
26
26
 
27
27
  - **iOS builds require Xcode 27+** (the iOS 27 SDK), even for apps that don't use any `mapConfig`/panel features — the library references `CPMapPanel`/`CPPanel` types internally behind `@available(iOS 27.0, *)` checks, but `@available` only defers *runtime* execution, not compile-time symbol resolution, so the SDK must be present to build at all.
28
+ - **`react-native-nitro-modules` 0.37.1 or newer** — the generated native bindings target that runtime shape; an older nitro-modules install fails at native build time.
28
29
 
29
30
  ## Installation
30
31
 
@@ -474,10 +475,11 @@ Use the color `'default'` for every monochrome icon that has to stay readable in
474
475
 
475
476
  ### 1. Register the AutoPlay Components
476
477
 
477
- You need to register your AutoPlay components in your app's entry file (e.g., `index.js`). This includes setting up the headless task that runs when CarPlay or Android Auto is connected.
478
+ You need to register your AutoPlay components in your app's entry file (e.g., `index.js`). Import `@iternio/react-native-auto-play/installTimers` — a side-effect-only module that replaces the global `setTimeout`/`setInterval`/`requestAnimationFrame` (and their `clear*`/`cancel*` counterparts) with versions that keep running while CarPlay/Android Auto is actively driving the car screen, even if the phone itself is backgrounded or its screen is locked. React Native's own timers throttle or pause in that state regardless of whether the app process is actually still alive, which would otherwise stall ETA updates and telemetry polling. It must run before any other module has a chance to capture a reference to the original globals, which means it must be your entry file's **first import** — ES import declarations are hoisted and evaluated in source order, so it needs to come before everything else, including `react-native` itself:
478
479
 
479
480
  ```javascript
480
481
  // index.js
482
+ import '@iternio/react-native-auto-play/installTimers';
481
483
  import { AppRegistry } from 'react-native';
482
484
  import { name as appName } from './app.json';
483
485
  import App from './src/App';
@@ -680,7 +682,7 @@ Below is a concise overview of the most important props per template. Optional p
680
682
 
681
683
  | Prop | Type | Required | Notes |
682
684
  | --- | --- | --- | --- |
683
- | `signInMethod` | `SignInMethod` | ✅ | The sign-in method configuration. Can be QRSignIn, PinSignIn, InputSignIn. |
685
+ | `signInMethod` | `SignInMethod` | ✅ | The sign-in method configuration. Can be QRSignIn, PinSignIn, InputSignIn, GoogleSignIn. |
684
686
  | `title` | `string` | ❌ | Header title. |
685
687
  | `additionalText` | `string` | ❌ | Additional descriptive text. |
686
688
  | `instructions` | `string` | ❌ | Sign-in Instructions text. |
@@ -694,6 +696,19 @@ Below is a concise overview of the most important props per template. Optional p
694
696
  | QR | `QrSignIn` | QR Code sign in |
695
697
  | PIN | `PinSignIn` | PIN Code sign in (1–12 characters) |
696
698
  | Input | `InputSignIn` | Text sign in, for example mail/username and password |
699
+ | Google | `GoogleSignIn` | Sign in with Google. Requires Google Play services 23.08 or newer — check `SignInTemplate.isGoogleSignInAvailable()` first. |
700
+
701
+ `GoogleSignIn` takes a `serverClientId` (your **Web** OAuth client ID), a `signInButtonText` and a `callback(error?, account?)`. On success the returned `GoogleSignInAccount` always carries both `idToken` and `serverAuthCode` (offline access, `openid` `profile` `email` scopes) for your backend. If the user cancels, or either the account picker or the authorization step fails, `callback` is called with an `error` and no account.
702
+
703
+ **Sign in with Google needs a recent Play services.** Constructing a `SignInTemplate` with `GoogleSignIn` throws `playServicesUnavailable` (and `updateTemplate` rejects with it) when Google Play services is missing or older than 23.08 (e.g. Android Automotive builds without GMS). Pick a different method up front instead:
704
+
705
+ ```ts
706
+ const signInMethod: SignInMethod = SignInTemplate.isGoogleSignInAvailable()
707
+ ? { method: SignInMethods.GOOGLE, serverClientId, signInButtonText: 'Sign in with Google', callback }
708
+ : { method: SignInMethods.QR, url: loginUrl };
709
+ ```
710
+
711
+ `isGoogleSignInAvailable()` always returns `false` on iOS.
697
712
 
698
713
  For InputSignIn the keyboard and input fields can be configured with following properties:
699
714
 
@@ -1314,8 +1329,6 @@ The same no-op surface is what `react-native-web` builds get automatically via `
1314
1329
 
1315
1330
  - **Broken exceptions with `react-native-skia`**: When using `react-native-skia` exceptions on iOS are not reported correctly. This is fixed since version `2.4.19` of `react-native-skia`. For more details, see this [pull request](https://github.com/Shopify/react-native-skia/pull/3595) and [issue](https://github.com/Shopify/react-native-skia/issues/3635).
1316
1331
  - **AppState on iOS**: The `AppState` module from React Native does not work correctly on iOS because this library uses scenes, which are not supported by the stock `AppState` module. This library provides a custom state listener that works for both Android and iOS. Use `HybridAutoPlay.addListenerRenderState` instead of `AppState`.
1317
- - **Timers stop on screen lock**: iOS stops all timers when the device main screen is turned off. To ensure timers continue to run (which is often necessary for background tasks related to autoplay), a patch for `react-native` is required. A patch is included in the root `patches/` directory and can be applied using `patch-package`.
1318
- In case you are using Expo SDK >= 56 make sure to set `buildReactNativeFromSource` to `true` in your app config for [expo-build-properties](https://docs.expo.dev/versions/latest/sdk/build-properties/#sharedbuildconfigfields), otherwise the patch can't be applied.
1319
1332
  - **expo-splash-screen stuck on iOS**: The `expo-splash-screen` module is broken on iOS because it does not support scenes, which are used by this library. This can cause the splash screen to be stuck on either the mobile device or on CarPlay. To fix this, a patch for `expo-splash-screen` is included in the root `patches/` directory and can be applied using `patch-package`. After applying the patch, you can hide the splash screen for a specific scene by passing the module name to the `hide` or `hideAsync` function. The module name can be one of the values from the `AutoPlayModules` enum or the UUID of a cluster screen.
1320
1333
  ```tsx
1321
1334
  import { hideAsync } from 'expo-splash-screen';
@@ -165,7 +165,9 @@ dependencies {
165
165
  implementation "androidx.car.app:app-projected:1.7.0"
166
166
  }
167
167
 
168
- implementation 'com.google.android.gms:play-services-base:18.10.0'
169
- implementation 'com.google.android.gms:play-services-auth:21.5.1'
168
+ implementation 'com.google.android.gms:play-services-auth:22.0.0'
169
+ implementation 'androidx.credentials:credentials:1.6.0'
170
+ implementation 'androidx.credentials:credentials-play-services-auth:1.6.0'
171
+ implementation 'com.google.android.libraries.identity.googleid:googleid:1.1.1'
170
172
  }
171
173
 
@@ -58,8 +58,6 @@
58
58
  </intent-filter>
59
59
  </service>
60
60
 
61
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
62
-
63
61
  <activity android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.SignInWithGoogleActivity" />
64
62
 
65
63
  <provider
@@ -74,8 +74,6 @@
74
74
  </intent-filter>
75
75
  </service>
76
76
 
77
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
78
-
79
77
  <activity android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.SignInWithGoogleActivity" />
80
78
 
81
79
  <provider
@@ -28,8 +28,6 @@
28
28
  <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc" tools:ignore="MetadataTagInsideApplicationTag" />
29
29
  <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" />
30
30
 
31
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
32
-
33
31
  <provider android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.ActivityRenderStateProvider" android:authorities="${applicationId}.ActivityRenderStateProvider" android:exported="false" />
34
32
  </application>
35
33
  </manifest>
@@ -37,8 +37,6 @@
37
37
  <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc" tools:ignore="MetadataTagInsideApplicationTag" />
38
38
  <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" />
39
39
 
40
- <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
41
-
42
40
  <provider android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.ActivityRenderStateProvider" android:authorities="${applicationId}.ActivityRenderStateProvider" android:exported="false" />
43
41
  </application>
44
42
  </manifest>
@@ -5,14 +5,10 @@ import android.annotation.SuppressLint
5
5
  import android.app.Notification
6
6
  import android.app.NotificationChannel
7
7
  import android.app.NotificationManager
8
- import android.content.ComponentName
9
- import android.content.Intent
10
- import android.content.ServiceConnection
11
8
  import android.content.pm.ApplicationInfo
12
9
  import android.content.pm.PackageManager
13
10
  import android.graphics.Bitmap
14
11
  import android.os.Build
15
- import android.os.IBinder
16
12
  import android.util.Log
17
13
  import androidx.car.app.CarAppService
18
14
  import androidx.car.app.Session
@@ -23,6 +19,7 @@ import androidx.core.app.NotificationCompat
23
19
  import androidx.core.app.NotificationManagerCompat
24
20
  import androidx.lifecycle.DefaultLifecycleObserver
25
21
  import androidx.lifecycle.LifecycleOwner
22
+ import com.facebook.react.ReactApplication
26
23
  import com.facebook.react.bridge.LifecycleEventListener
27
24
  import com.margelo.nitro.NitroModules
28
25
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
@@ -30,7 +27,6 @@ import com.margelo.nitro.swe.iternio.reactnativeautoplay.utils.AppInfo
30
27
  class AndroidAutoService : CarAppService() {
31
28
  private lateinit var notificationManager: NotificationManager
32
29
 
33
- private var isServiceBound = false
34
30
  private var isSessionStarted = false
35
31
  private var isReactAppStarted = false
36
32
 
@@ -48,6 +44,8 @@ class AndroidAutoService : CarAppService() {
48
44
  super.onCreate()
49
45
  instance = this
50
46
 
47
+ (application as? ReactApplication)?.reactHost?.start()
48
+
51
49
  NitroModules.applicationContext?.addLifecycleEventListener(reactLifecycleObserver)
52
50
 
53
51
  notificationManager = getSystemService(NotificationManager::class.java)
@@ -98,11 +96,6 @@ class AndroidAutoService : CarAppService() {
98
96
  }
99
97
 
100
98
  private val sessionLifecycleObserver = object : DefaultLifecycleObserver {
101
- override fun onCreate(owner: LifecycleOwner) {
102
- val serviceIntent = Intent(applicationContext, HeadlessTaskService::class.java)
103
- bindService(serviceIntent, connection, BIND_AUTO_CREATE)
104
- }
105
-
106
99
  override fun onResume(owner: LifecycleOwner) {
107
100
  isSessionStarted = true
108
101
  }
@@ -112,27 +105,10 @@ class AndroidAutoService : CarAppService() {
112
105
  }
113
106
 
114
107
  override fun onDestroy(owner: LifecycleOwner) {
115
- if (isServiceBound) {
116
- unbindService(connection)
117
- isServiceBound = false
118
- }
119
-
120
108
  this@AndroidAutoService.stopForeground(STOP_FOREGROUND_REMOVE)
121
109
  }
122
110
  }
123
111
 
124
- private val connection: ServiceConnection = object : ServiceConnection {
125
- override fun onServiceConnected(
126
- className: ComponentName, service: IBinder
127
- ) {
128
- isServiceBound = true
129
- }
130
-
131
- override fun onServiceDisconnected(arg0: ComponentName) {
132
- isServiceBound = false
133
- }
134
- }
135
-
136
112
  private fun createNotification(
137
113
  title: String?, text: String?, largeIcon: Bitmap?
138
114
  ): Notification {
@@ -8,3 +8,7 @@ class TemplateNotFoundException(private val templateId: String) :
8
8
  class VoiceInputCancelledException : Exception("voiceInputCancelled") {
9
9
  override fun toString(): String = "voiceInputCancelled"
10
10
  }
11
+
12
+ class PlayServicesUnavailableException : Exception("playServicesUnavailable") {
13
+ override fun toString(): String = "playServicesUnavailable"
14
+ }
@@ -0,0 +1,122 @@
1
+ package com.margelo.nitro.swe.iternio.reactnativeautoplay
2
+
3
+ import android.os.Handler
4
+ import android.os.Looper
5
+ import android.os.SystemClock
6
+ import java.lang.ref.WeakReference
7
+ import java.util.concurrent.ConcurrentHashMap
8
+ import java.util.concurrent.atomic.AtomicBoolean
9
+ import java.util.concurrent.atomic.AtomicLong
10
+
11
+ private class ScheduledTimer(
12
+ val callback: () -> Unit,
13
+ val interval: Long,
14
+ val repeats: Boolean,
15
+ var target: Long,
16
+ )
17
+
18
+ // Weak ref, so a stale instance (dev reload / host restart) can't tick forever in the queue.
19
+ private class TickRunnable(target: HybridAutoPlayTiming) : Runnable {
20
+ private val ref = WeakReference(target)
21
+
22
+ override fun run() {
23
+ ref.get()?.tick()
24
+ }
25
+ }
26
+
27
+ /**
28
+ * Backs setTimeout/setInterval (see AutoPlayTimers.ts) with a plain Handler loop on the main
29
+ * Looper -- not Choreographer, which JavaTimerManager itself uses and only keeps ticking while
30
+ * the host is resumed or a headless JS task is running. See AutoPlayTiming.nitro.ts.
31
+ *
32
+ * Ticks at a fixed ~60Hz while any timer is pending and stops entirely once idle, rather than
33
+ * scheduling a delay to the next due target: postDelayed's dispatch is gated on uptimeMillis(),
34
+ * which pauses during deep sleep, so a long pre-sleep delay would need that much *awake* time
35
+ * after waking. A short, repeated delay only needs ~16ms of awake time, so it fires within
36
+ * about one frame of the device waking regardless of sleep length -- due timers are then found
37
+ * correctly because target/now use elapsedRealtime(), which counts straight through sleep.
38
+ */
39
+ class HybridAutoPlayTiming : HybridAutoPlayTimingSpec() {
40
+ companion object {
41
+ private const val FRAME_DURATION_MS = 1000L / 60L
42
+
43
+ // RN's TimerManager also numbers ids from 1; offsetting avoids collisions with ids a
44
+ // pre-install caller (e.g. React's own scheduler) still holds against the original
45
+ // clearTimeout, now replaced.
46
+ private const val ID_OFFSET = 1_000_000_000L
47
+ }
48
+
49
+ private val handler = Handler(Looper.getMainLooper())
50
+ private val timers = ConcurrentHashMap<Double, ScheduledTimer>()
51
+ private val nextId = AtomicLong(ID_OFFSET)
52
+ private val isTicking = AtomicBoolean(false)
53
+ private val tickRunnable = TickRunnable(this)
54
+
55
+ private fun ensureTicking() {
56
+ if (isTicking.compareAndSet(false, true)) {
57
+ handler.postDelayed(tickRunnable, FRAME_DURATION_MS)
58
+ }
59
+ }
60
+
61
+ internal fun tick() {
62
+ // elapsedRealtime(), not uptimeMillis(): both are immune to NTP/manual clock changes,
63
+ // but unlike uptimeMillis() this one keeps counting through deep sleep.
64
+ val now = SystemClock.elapsedRealtime()
65
+
66
+ // Sort by (target, id): ConcurrentHashMap iteration order is unspecified, so
67
+ // setTimeout(a, 0); setTimeout(b, 0) could otherwise fire b before a.
68
+ val dueIds = timers.entries.filter { it.value.target <= now }
69
+ .sortedWith(compareBy({ it.value.target }, { it.key }))
70
+ .map { it.key }
71
+
72
+ for (id in dueIds) {
73
+ // Re-check membership: a same-tick callback may have cleared a later timer in
74
+ // this snapshotted list (e.g. `clearTimeout(t); t = setTimeout(...)`).
75
+ val timer = timers[id] ?: continue
76
+
77
+ if (timer.repeats) {
78
+ timer.target = now + timer.interval
79
+ } else {
80
+ timers.remove(id)
81
+ }
82
+
83
+ timer.callback()
84
+ }
85
+
86
+ if (timers.isNotEmpty()) {
87
+ handler.postDelayed(tickRunnable, FRAME_DURATION_MS)
88
+ return
89
+ }
90
+
91
+ isTicking.set(false)
92
+ // Reclaim: a concurrent createTimer() may have inserted an entry and found `isTicking`
93
+ // still true (skipping its own post) in the gap before the flag was cleared above.
94
+ if (timers.isNotEmpty()) {
95
+ ensureTicking()
96
+ }
97
+ }
98
+
99
+ override fun createTimer(callback: () -> Unit, durationMs: Double, repeats: Boolean): Double {
100
+ val interval = durationMs.toLong().coerceAtLeast(0)
101
+ val id = nextId.getAndIncrement().toDouble()
102
+ timers[id] = ScheduledTimer(
103
+ callback = callback,
104
+ interval = interval,
105
+ repeats = repeats,
106
+ target = SystemClock.elapsedRealtime() + interval,
107
+ )
108
+ ensureTicking()
109
+ return id
110
+ }
111
+
112
+ override fun deleteTimer(id: Double) {
113
+ timers.remove(id)
114
+ }
115
+
116
+ override fun dispose() {
117
+ handler.removeCallbacks(tickRunnable)
118
+ isTicking.set(false)
119
+ timers.clear()
120
+ super.dispose()
121
+ }
122
+ }
@@ -1,5 +1,8 @@
1
1
  package com.margelo.nitro.swe.iternio.reactnativeautoplay
2
2
 
3
+ import com.google.android.gms.common.ConnectionResult
4
+ import com.google.android.gms.common.GoogleApiAvailability
5
+ import com.margelo.nitro.NitroModules
3
6
  import com.margelo.nitro.core.Promise
4
7
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.AndroidAutoTemplate
5
8
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.template.SignInTemplate
@@ -9,14 +12,34 @@ class HybridSignInTemplate : HybridSignInTemplateSpec() {
9
12
  val context = AndroidAutoSession.getRootContext()
10
13
  ?: throw IllegalArgumentException("createSignInTemplate failed, no carContext found")
11
14
 
15
+ assertSignInMethodAvailable(config)
16
+
12
17
  val template = SignInTemplate(context, config)
13
18
  AndroidAutoTemplate.setTemplate(config.id, template)
14
19
  }
15
20
 
16
21
  override fun updateTemplate(templateId: String, config: SignInTemplateConfig): Promise<Unit> {
17
22
  return Promise.async {
23
+ assertSignInMethodAvailable(config)
18
24
  val template = AndroidAutoTemplate.getTemplate<SignInTemplate>(templateId)
19
25
  template.updateTemplate(config)
20
26
  }
21
27
  }
28
+
29
+ override fun isGoogleSignInAvailable(): Boolean {
30
+ val context = NitroModules.applicationContext ?: return false
31
+
32
+ // on older versions sign in with google is no longer supported
33
+ val googleServiceMinVersion = 230815045
34
+ val available = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(
35
+ context, googleServiceMinVersion
36
+ )
37
+ return ConnectionResult.SUCCESS == available
38
+ }
39
+
40
+ private fun assertSignInMethodAvailable(config: SignInTemplateConfig) {
41
+ if (config.signInMethod?.asFourthOrNull() != null && !isGoogleSignInAvailable()) {
42
+ throw PlayServicesUnavailableException()
43
+ }
44
+ }
22
45
  }
@@ -4,42 +4,90 @@ import android.os.Binder
4
4
  import android.os.Bundle
5
5
  import android.os.IBinder
6
6
  import androidx.activity.ComponentActivity
7
- import androidx.activity.result.ActivityResult
7
+ import androidx.activity.result.IntentSenderRequest
8
8
  import androidx.activity.result.contract.ActivityResultContracts
9
- import com.google.android.gms.auth.api.signin.GoogleSignIn
10
- import com.google.android.gms.auth.api.signin.GoogleSignInAccount
11
- import com.google.android.gms.auth.api.signin.GoogleSignInOptions
9
+ import androidx.credentials.CredentialManager
10
+ import androidx.credentials.GetCredentialRequest
11
+ import androidx.lifecycle.lifecycleScope
12
+ import com.google.android.gms.auth.api.identity.AuthorizationRequest
13
+ import com.google.android.gms.auth.api.identity.Identity
14
+ import com.google.android.gms.common.Scopes
15
+ import com.google.android.gms.common.api.Scope
16
+ import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
17
+ import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
18
+ import kotlinx.coroutines.launch
12
19
  import java.security.InvalidParameterException
13
- import javax.annotation.Nullable
14
20
 
15
21
  class SignInWithGoogleActivity : ComponentActivity() {
16
- override fun onCreate(savedInstanceState: Bundle?) {
17
- super.onCreate(savedInstanceState)
18
22
 
19
- val signInCompleteCallback = intent.extras?.getBinder(BINDER_KEY) as OnSignInComplete?
23
+ private var callback: OnSignInComplete? = null
24
+ private var idCredential: GoogleIdTokenCredential? = null
25
+
26
+ private val authLauncher = registerForActivityResult(
27
+ ActivityResultContracts.StartIntentSenderForResult()
28
+ ) { result ->
29
+ val auth = runCatching {
30
+ Identity.getAuthorizationClient(this)
31
+ .getAuthorizationResultFromIntent(result.data)
32
+ }.getOrNull()
33
+ finishWith(auth?.serverAuthCode)
34
+ }
20
35
 
36
+ override fun onCreate(savedInstanceState: Bundle?) {
37
+ super.onCreate(savedInstanceState)
38
+ callback = intent.extras?.getBinder(BINDER_KEY) as OnSignInComplete?
21
39
  val serverClientId = intent.extras?.getString("serverClientId")
22
40
  ?: throw InvalidParameterException("missing serverClientId parameter")
23
41
 
24
- val activityResultLauncher = registerForActivityResult(
25
- ActivityResultContracts.StartActivityForResult()
26
- ) { result: ActivityResult ->
27
- val account = GoogleSignIn.getSignedInAccountFromIntent(
28
- result.data
29
- ).result
30
- signInCompleteCallback?.onSignInComplete(account)
31
- finish()
32
- }
42
+ lifecycleScope.launch {
43
+ // 1. Authentication: ID token
44
+ val request = GetCredentialRequest.Builder()
45
+ .addCredentialOption(GetSignInWithGoogleOption.Builder(serverClientId).build())
46
+ .build()
47
+ try {
48
+ val result = CredentialManager.create(this@SignInWithGoogleActivity)
49
+ .getCredential(this@SignInWithGoogleActivity, request)
50
+ idCredential = GoogleIdTokenCredential.createFrom(result.credential.data)
51
+ } catch (_: Exception) {
52
+ callback?.onSignInComplete(null, null)
53
+ finish()
54
+ return@launch
55
+ }
33
56
 
34
- val googleSignInClient = GoogleSignIn.getClient(
35
- this,
36
- GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
37
- .requestServerAuthCode(serverClientId)
38
- .requestEmail()
39
- .requestIdToken(serverClientId)
57
+ // 2. Authorization: server auth code
58
+ val authRequest = AuthorizationRequest.builder()
59
+ // matches the legacy DEFAULT_SIGN_IN + requestEmail() scopes, so the exchanged
60
+ // server auth code grants the same access as before the Credential Manager migration
61
+ .setRequestedScopes(
62
+ listOf(Scope(Scopes.OPEN_ID), Scope(Scopes.PROFILE), Scope(Scopes.EMAIL))
63
+ )
64
+ .requestOfflineAccess(serverClientId)
40
65
  .build()
41
- )
42
- activityResultLauncher.launch(googleSignInClient.signInIntent)
66
+ Identity.getAuthorizationClient(this@SignInWithGoogleActivity)
67
+ .authorize(authRequest)
68
+ .addOnSuccessListener { res ->
69
+ if (res.hasResolution()) {
70
+ authLauncher.launch(
71
+ IntentSenderRequest.Builder(res.pendingIntent!!.intentSender).build()
72
+ )
73
+ } else {
74
+ finishWith(res.serverAuthCode)
75
+ }
76
+ }
77
+ .addOnFailureListener { finishWith(null) }
78
+ }
79
+ }
80
+
81
+ private fun finishWith(serverAuthCode: String?) {
82
+ // a cancelled or failed authorization step yields no server auth code; report it as a
83
+ // failed sign in so callers get either an error or a complete account, as with the
84
+ // legacy GoogleSignIn flow, never an account without a server auth code
85
+ if (serverAuthCode == null) {
86
+ callback?.onSignInComplete(null, null)
87
+ } else {
88
+ callback?.onSignInComplete(idCredential, serverAuthCode)
89
+ }
90
+ finish()
43
91
  }
44
92
 
45
93
  /**
@@ -49,9 +97,13 @@ class SignInWithGoogleActivity : ComponentActivity() {
49
97
  /**
50
98
  * Notifies that sign in flow completed.
51
99
  *
52
- * @param account the account signed in or `null` if there were issues signing in.
100
+ * @param credential the account signed in or `null` if there were issues signing in.
101
+ * @param serverAuthCode the server auth code, always non-null when [credential] is non-null.
53
102
  */
54
- abstract fun onSignInComplete(@Nullable account: GoogleSignInAccount?)
103
+ abstract fun onSignInComplete(
104
+ credential: GoogleIdTokenCredential?,
105
+ serverAuthCode: String?
106
+ )
55
107
  }
56
108
 
57
109
  companion object {
@@ -378,7 +378,7 @@ object Parser {
378
378
  }
379
379
  row.onPress?.let {
380
380
  setOnClickListener {
381
- row.onPress(null)
381
+ it(null)
382
382
  }
383
383
  }
384
384
  row.browsable?.let {
@@ -650,7 +650,7 @@ object Parser {
650
650
  // whose backing bitmap has already been recycled or failed to allocate;
651
651
  // copy() can also throw (e.g., OOM on very large remote images). Either
652
652
  // way we return null so the caller falls back to a placeholder icon.
653
- return image.underlyingBitmap.copy(Bitmap.Config.ARGB_8888, false)
653
+ return image.underlyingBitmap?.copy(Bitmap.Config.ARGB_8888, false)
654
654
  } else if (image is CloseableXml) {
655
655
  val drawable = image.buildDrawable()
656
656
  return drawable?.toBitmap(
@@ -1,8 +1,8 @@
1
1
  package com.margelo.nitro.swe.iternio.reactnativeautoplay.template
2
2
 
3
3
  import android.content.Intent
4
- import android.net.Uri
5
4
  import android.os.Bundle
5
+ import android.util.Base64
6
6
  import androidx.car.app.CarContext
7
7
  import androidx.car.app.model.Action
8
8
  import androidx.car.app.model.ActionStrip
@@ -18,7 +18,9 @@ import androidx.car.app.model.signin.ProviderSignInMethod
18
18
  import androidx.car.app.model.signin.QRCodeSignInMethod
19
19
  import androidx.car.app.model.signin.SignInTemplate
20
20
  import androidx.core.graphics.drawable.IconCompat
21
- import com.google.android.gms.auth.api.signin.GoogleSignInAccount
21
+ import androidx.core.net.toUri
22
+ import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
23
+ import com.margelo.nitro.NitroModules
22
24
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.KeyboardType
23
25
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.NitroAction
24
26
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.NitroActionType
@@ -26,8 +28,8 @@ import com.margelo.nitro.swe.iternio.reactnativeautoplay.R
26
28
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.SignInTemplateConfig
27
29
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.SignInWithGoogleActivity
28
30
  import com.margelo.nitro.swe.iternio.reactnativeautoplay.TextInputType
31
+ import org.json.JSONObject
29
32
  import java.security.InvalidParameterException
30
- import androidx.core.net.toUri
31
33
 
32
34
  class SignInTemplate(
33
35
  context: CarContext, config: SignInTemplateConfig
@@ -115,32 +117,35 @@ class SignInTemplate(
115
117
  ).build()
116
118
  )
117
119
  setOnClickListener(ParkedOnlyOnClickListener.create {
118
- val extras = Bundle(1)
120
+ val extras = Bundle(2)
119
121
  extras.putBinder(
120
122
  SignInWithGoogleActivity.BINDER_KEY,
121
123
  object : SignInWithGoogleActivity.OnSignInComplete() {
122
- override fun onSignInComplete(account: GoogleSignInAccount?) {
123
- if (account == null) {
124
+ override fun onSignInComplete(
125
+ credential: GoogleIdTokenCredential?,
126
+ serverAuthCode: String?
127
+ ) {
128
+ if (credential == null) {
124
129
  googleSignIn.callback("Error signing in", null)
125
- } else {
126
- googleSignIn.callback(
127
- null,
128
- com.margelo.nitro.swe.iternio.reactnativeautoplay.GoogleSignInAccount(
129
- serverAuthCode = account.serverAuthCode,
130
- email = account.email,
131
- id = account.id,
132
- displayName = account.displayName,
133
- photoUrl = account.photoUrl?.toString(),
134
- idToken = account.idToken,
135
- givenName = account.givenName,
136
- familyName = account.familyName
137
- )
138
- )
130
+ return
139
131
  }
132
+ googleSignIn.callback(
133
+ null,
134
+ com.margelo.nitro.swe.iternio.reactnativeautoplay.GoogleSignInAccount(
135
+ serverAuthCode = serverAuthCode,
136
+ email = credential.id,
137
+ id = subFromIdToken(credential.idToken),
138
+ displayName = credential.displayName,
139
+ photoUrl = credential.profilePictureUri?.toString(),
140
+ idToken = credential.idToken,
141
+ givenName = credential.givenName,
142
+ familyName = credential.familyName
143
+ )
144
+ )
140
145
  }
141
146
  })
142
147
  extras.putString("serverClientId", googleSignIn.serverClientId)
143
- context.startActivity(
148
+ NitroModules.applicationContext?.startActivity(
144
149
  Intent().setClass(context, SignInWithGoogleActivity::class.java)
145
150
  .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).putExtras(extras)
146
151
  )
@@ -211,4 +216,13 @@ class SignInTemplate(
211
216
  config.onPopped?.let { it() }
212
217
  templates.remove(templateId)
213
218
  }
219
+
220
+ private fun subFromIdToken(idToken: String): String? = runCatching {
221
+ val payload = idToken.split(".")[1]
222
+ val json = String(
223
+ Base64.decode(payload, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP),
224
+ Charsets.UTF_8
225
+ )
226
+ JSONObject(json).getString("sub")
227
+ }.getOrNull()
214
228
  }
@@ -0,0 +1,3 @@
1
+ // Root re-export so `@iternio/react-native-auto-play/installTimers` is a deliberate, explicitly
2
+ // published public entry point rather than a reach into src/ internals -- see src/installTimers.ts.
3
+ import './src/installTimers';
@@ -0,0 +1,2 @@
1
+ // Web/Jest counterpart to installTimers.ts, picked by Metro's platform resolution.
2
+ import './src/installTimers.web';