@iternio/react-native-auto-play 0.5.9 → 0.5.10

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.
package/README.md CHANGED
@@ -206,6 +206,14 @@ In case you have ProGuard enabled (`def enableProguardInReleaseBuilds = true` in
206
206
  ### Android Auto Customization
207
207
  You can customize certain behaviors of the library on Android Auto by setting properties in your app's `android/gradle.properties` file.
208
208
 
209
+ - **App Category**: Declare which Android Auto / Automotive app type the `CarAppService` advertises — the Android counterpart to choosing your CarPlay scene type in `Info.plist`.
210
+ ```properties
211
+ ReactNativeAutoPlay_androidAutoAppCategory=navigation
212
+ ```
213
+ Supported values are `navigation`, `poi`, `parking`, `charging`, `iot`, `messaging`, `calling`, and `weather` (see the [supported app categories](https://developer.android.com/training/cars)); each maps to `androidx.car.app.category.<UPPERCASE>`. An unrecognized value fails the build. The default `navigation` keeps the existing behavior. Any other value selects a lean manifest that declares the chosen category and omits the navigation-only permissions (`NAVIGATION_TEMPLATES`, `MAP_TEMPLATES`, `ACCESS_SURFACE`), the `FEATURE_CLUSTER` category, and the `NAVIGATE`/`geo` intent filters — a non-navigation, no-map template app needs none of these, and declaring them gets the app reviewed against the navigation-app bar on the Play Store.
214
+
215
+ On Android Automotive, the app-focus helpers on `HybridAndroidAutomotive` (`requestAppFocus`, `registerAppFocusListener`, `getAppFocusState`) request/observe **navigation** focus specifically; they are meant for navigation apps and should not be used with a non-navigation category.
216
+
209
217
  - **Telemetry Update Interval**: Control how often telemetry data is updated.
210
218
  ```properties
211
219
  ReactNativeAutoPlay_androidTelemetryUpdateInterval=4000
@@ -28,6 +28,11 @@ def getExtOrIntegerDefault(name) {
28
28
  return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReactNativeAutoPlay_" + name]).toInteger()
29
29
  }
30
30
 
31
+ // Non-navigation categories select the lean manifest (AndroidManifest-nonnav.xml).
32
+ def androidAutoAppCategory = getExtOrDefault("androidAutoAppCategory").toString().trim().toLowerCase(java.util.Locale.ROOT)
33
+ def validAndroidAutoCategories = ['navigation', 'poi', 'parking', 'charging', 'iot', 'messaging', 'calling', 'weather']
34
+ def isNavigationApp = androidAutoAppCategory == "navigation"
35
+
31
36
  android {
32
37
  namespace "com.margelo.nitro.swe.iternio.reactnativeautoplay"
33
38
 
@@ -35,6 +40,10 @@ android {
35
40
  compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
36
41
 
37
42
  defaultConfig {
43
+ if (!validAndroidAutoCategories.contains(androidAutoAppCategory)) {
44
+ throw new GradleException("Invalid ReactNativeAutoPlay_androidAutoAppCategory '${androidAutoAppCategory}'. Must be one of: ${validAndroidAutoCategories.join(', ')}")
45
+ }
46
+
38
47
  minSdkVersion getExtOrIntegerDefault("minSdkVersion")
39
48
  targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
40
49
 
@@ -55,6 +64,9 @@ android {
55
64
  }
56
65
  }
57
66
 
67
+ manifestPlaceholders.autoPlayAppCategory = "androidx.car.app.category." + androidAutoAppCategory.toUpperCase(java.util.Locale.ROOT)
68
+
69
+ buildConfigField "boolean", "IS_NAVIGATION_APP", isNavigationApp.toString()
58
70
  buildConfigField "float", "SCALE_FACTOR", getExtOrDefault("androidAutoScaleFactor")
59
71
  buildConfigField "long", "TELEMETRY_UPDATE_INTERVAL", getExtOrDefault("androidTelemetryUpdateInterval")
60
72
  buildConfigField "long", "CLUSTER_SPLASH_DELAY_MS", getExtOrDefault("clusterSplashDelayMs")
@@ -117,10 +129,10 @@ android {
117
129
 
118
130
  if (getExtOrDefault("isAutomotiveApp") == "true") {
119
131
  java.srcDirs += 'src/automotive/java'
120
- manifest.srcFile 'src/automotive/AndroidManifest.xml'
132
+ manifest.srcFile isNavigationApp ? 'src/automotive/AndroidManifest.xml' : 'src/automotive/AndroidManifest-nonnav.xml'
121
133
  } else {
122
134
  java.srcDirs += 'src/auto/java'
123
- manifest.srcFile 'src/main/AndroidManifest.xml'
135
+ manifest.srcFile isNavigationApp ? 'src/main/AndroidManifest.xml' : 'src/main/AndroidManifest-nonnav.xml'
124
136
  }
125
137
  }
126
138
  }
@@ -5,6 +5,8 @@ ReactNativeAutoPlay_compileSdkVersion=36
5
5
  ReactNativeAutoPlay_ndkVersion=27.1.12297006
6
6
  # specifies if the Android Auto (androidx.car.app:app-projected) or Automotive (androidx.car.app:app-automotive) library is used
7
7
  ReactNativeAutoPlay_isAutomotiveApp=false
8
+ # Android Auto/Automotive app category -> androidx.car.app.category.<UPPERCASE>. Non-navigation values use a lean manifest.
9
+ ReactNativeAutoPlay_androidAutoAppCategory=navigation
8
10
  # apply a scale factor on the root view that affects everything rendered by react-native, does not affect templates
9
11
  ReactNativeAutoPlay_androidAutoScaleFactor=1.5f
10
12
  ReactNativeAutoPlay_androidTelemetryUpdateInterval=4000
@@ -0,0 +1,78 @@
1
+ <!-- Non-navigation Android Automotive manifest; see AndroidManifest.xml for the navigation variant. -->
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
3
+
4
+ <uses-feature
5
+ android:name="android.hardware.type.automotive"
6
+ android:required="true" />
7
+
8
+ <uses-feature
9
+ android:name="android.software.car.templates_host"
10
+ android:required="true" />
11
+
12
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
13
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
14
+
15
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
16
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
17
+
18
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
19
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
20
+
21
+
22
+ <!-- Android Automotive specific permissions -->
23
+ <uses-permission android:name="android.car.permission.CAR_ENERGY" />
24
+ <uses-permission android:name="android.car.permission.CAR_ENERGY_PORTS" />
25
+ <uses-permission android:name="android.car.permission.CAR_EXTERIOR_ENVIRONMENT" />
26
+ <uses-permission android:name="android.car.permission.CAR_IDENTIFICATION" />
27
+ <uses-permission android:name="android.car.permission.CAR_INFO" />
28
+ <uses-permission android:name="android.car.permission.CAR_POWERTRAIN" />
29
+ <uses-permission android:name="android.car.permission.CAR_SPEED" />
30
+
31
+ <application>
32
+ <activity
33
+ android:name="androidx.car.app.activity.CarAppActivity"
34
+ android:exported="true"
35
+ android:launchMode="singleTask"
36
+ android:theme="@android:style/Theme.DeviceDefault.NoActionBar">
37
+
38
+ <intent-filter>
39
+ <action android:name="android.intent.action.MAIN" />
40
+
41
+ <category android:name="android.intent.category.LAUNCHER" />
42
+ </intent-filter>
43
+
44
+ <meta-data
45
+ android:name="distractionOptimized"
46
+ android:value="true" />
47
+
48
+ </activity>
49
+
50
+ <service
51
+ android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.AndroidAutoService"
52
+ android:exported="true"
53
+ android:foregroundServiceType="location">
54
+ <intent-filter>
55
+ <action android:name="androidx.car.app.CarAppService" />
56
+
57
+ <category android:name="${autoPlayAppCategory}" />
58
+ </intent-filter>
59
+ </service>
60
+
61
+ <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
62
+
63
+ <activity android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.SignInWithGoogleActivity" />
64
+
65
+ <provider
66
+ android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.ActivityRenderStateProvider"
67
+ android:authorities="${applicationId}.ActivityRenderStateProvider"
68
+ android:exported="false" />
69
+
70
+ <meta-data
71
+ android:name="com.android.automotive"
72
+ android:resource="@xml/automotive_app_desc" />
73
+ <meta-data
74
+ android:name="androidx.car.app.minCarApiLevel"
75
+ android:value="1" />
76
+ </application>
77
+
78
+ </manifest>
@@ -0,0 +1,35 @@
1
+ <!-- Non-navigation Android Auto manifest; see AndroidManifest.xml for the navigation variant. -->
2
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+ xmlns:tools="http://schemas.android.com/tools">
4
+
5
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
6
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
7
+
8
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
9
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
10
+
11
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
12
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
13
+
14
+ <!-- Android Auto specific permissions -->
15
+ <uses-permission android:name="com.google.android.gms.permission.CAR_FUEL" />
16
+ <uses-permission android:name="com.google.android.gms.permission.CAR_MILEAGE" />
17
+ <uses-permission android:name="com.google.android.gms.permission.CAR_SPEED" />
18
+
19
+ <application>
20
+ <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.AndroidAutoService" android:exported="true" android:foregroundServiceType="location">
21
+ <intent-filter>
22
+ <action android:name="androidx.car.app.CarAppService" />
23
+
24
+ <category android:name="${autoPlayAppCategory}" />
25
+ </intent-filter>
26
+ </service>
27
+
28
+ <meta-data android:name="com.google.android.gms.car.application" android:resource="@xml/automotive_app_desc" tools:ignore="MetadataTagInsideApplicationTag" />
29
+ <meta-data android:name="androidx.car.app.minCarApiLevel" android:value="1" />
30
+
31
+ <service android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.HeadlessTaskService" />
32
+
33
+ <provider android:name="com.margelo.nitro.swe.iternio.reactnativeautoplay.ActivityRenderStateProvider" android:authorities="${applicationId}.ActivityRenderStateProvider" android:exported="false" />
34
+ </application>
35
+ </manifest>
@@ -136,9 +136,14 @@ class AndroidAutoService : CarAppService() {
136
136
  private fun createNotification(
137
137
  title: String?, text: String?, largeIcon: Bitmap?
138
138
  ): Notification {
139
+ val notificationCategory = if (BuildConfig.IS_NAVIGATION_APP) {
140
+ NotificationCompat.CATEGORY_NAVIGATION
141
+ } else {
142
+ NotificationCompat.CATEGORY_SERVICE
143
+ }
139
144
  return NotificationCompat.Builder(this, CHANNEL_ID)
140
145
  .setSmallIcon(R.drawable.ic_notification).setOngoing(true)
141
- .setCategory(NotificationCompat.CATEGORY_NAVIGATION).setOnlyAlertOnce(true)
146
+ .setCategory(notificationCategory).setOnlyAlertOnce(true)
142
147
  .setWhen(System.currentTimeMillis()).setPriority(NotificationManager.IMPORTANCE_LOW)
143
148
  .extend(
144
149
  CarAppExtender.Builder().setImportance(NotificationManagerCompat.IMPORTANCE_LOW)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iternio/react-native-auto-play",
3
- "version": "0.5.9",
3
+ "version": "0.5.10",
4
4
  "description": "Android Auto and Apple CarPlay for react-native",
5
5
  "main": "lib/index",
6
6
  "module": "lib/index",
@@ -1,2 +0,0 @@
1
- import type { AutoPlay } from './specs/AutoPlay.nitro';
2
- export declare const HybridAutoPlay: AutoPlay;
@@ -1,2 +0,0 @@
1
- import { NitroModules } from 'react-native-nitro-modules';
2
- export const HybridAutoPlay = NitroModules.createHybridObject('AutoPlay');
@@ -1,10 +0,0 @@
1
- type Props = {
2
- children: React.ReactNode;
3
- moduleName: string;
4
- };
5
- /**
6
- * renders the passed children when the specified scene/screen appeared
7
- * this makes sure child hooks are executed only when the map template is ready
8
- */
9
- export default function OnAppearedChildRenderer({ children, moduleName }: Props): import("react").ReactNode;
10
- export {};
@@ -1,26 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { HybridAutoPlay } from '../hybrid/HybridAutoPlay';
3
- /**
4
- * renders the passed children when the specified scene/screen appeared
5
- * this makes sure child hooks are executed only when the map template is ready
6
- */
7
- export default function OnAppearedChildRenderer({ children, moduleName }) {
8
- const [didAppear, setDidAppear] = useState(false);
9
- useEffect(() => {
10
- let remove = HybridAutoPlay.addListenerRenderState(moduleName, (renderState) => {
11
- if (renderState === 'didAppear') {
12
- remove?.();
13
- remove = null;
14
- setDidAppear(true);
15
- }
16
- });
17
- return () => {
18
- remove?.();
19
- remove = null;
20
- };
21
- }, [moduleName]);
22
- if (didAppear) {
23
- return children;
24
- }
25
- return null;
26
- }
@@ -1,7 +0,0 @@
1
- /**
2
- * A hook to determine if the CarPlay/Android Auto screen is currently focused (visible).
3
- *
4
- * @param moduleName The name of the module to listen to.
5
- * @returns `true` if the screen is focused, `false` otherwise.
6
- */
7
- export declare function useIsAutoPlayFocused(moduleName: string): boolean;
@@ -1,20 +0,0 @@
1
- import { useEffect, useState } from 'react';
2
- import { HybridAutoPlay } from '..';
3
- /**
4
- * A hook to determine if the CarPlay/Android Auto screen is currently focused (visible).
5
- *
6
- * @param moduleName The name of the module to listen to.
7
- * @returns `true` if the screen is focused, `false` otherwise.
8
- */
9
- export function useIsAutoPlayFocused(moduleName) {
10
- const [isFocused, setIsFocused] = useState(false);
11
- useEffect(() => {
12
- const remove = HybridAutoPlay.addListenerRenderState(moduleName, (state) => {
13
- setIsFocused(state === 'didAppear');
14
- });
15
- return () => {
16
- remove();
17
- };
18
- }, [moduleName]);
19
- return isFocused;
20
- }
package/lib/hybrid.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import type { AutoPlay as NitroAutoPlay } from './specs/AutoPlay.nitro';
2
- export declare const HybridAutoPlay: NitroAutoPlay;
package/lib/hybrid.js DELETED
@@ -1,2 +0,0 @@
1
- import { NitroModules } from 'react-native-nitro-modules';
2
- export const HybridAutoPlay = NitroModules.createHybridObject('AutoPlay');
@@ -1,11 +0,0 @@
1
- import type { HybridObject } from 'react-native-nitro-modules';
2
- import type { NitroAutomotivePermissionRequestTemplateConfig } from '../templates/AutomotivePermissionRequestTemplate';
3
- import type { NitroTemplateConfig } from './AutoPlay.nitro';
4
- interface AutomotivePermissionRequestTemplateConfig extends NitroTemplateConfig, NitroAutomotivePermissionRequestTemplateConfig {
5
- }
6
- export interface AutomotivePermissionRequestTemplate extends HybridObject<{
7
- android: 'kotlin';
8
- }> {
9
- createAutomotivePermissionRequestTemplate(config: AutomotivePermissionRequestTemplateConfig): void;
10
- }
11
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,11 +0,0 @@
1
- import type { HybridObject } from 'react-native-nitro-modules';
2
- import type { NitroAutomotivePermissionRequestTemplateConfig } from '../templates/AutomotivePermissionRequestTemplate';
3
- import type { NitroTemplateConfig } from './AutoPlay.nitro';
4
- interface AutomotivePermissionRequestTemplateConfig extends NitroTemplateConfig, NitroAutomotivePermissionRequestTemplateConfig {
5
- }
6
- export interface AutomotivePermissionRequestTemplate extends HybridObject<{
7
- android: 'kotlin';
8
- }> {
9
- createAutomotivePermissionRequestTemplate(config: AutomotivePermissionRequestTemplateConfig): void;
10
- }
11
- export {};
@@ -1,23 +0,0 @@
1
- import type { CustomActionButtonAndroid } from '../types/Button';
2
- import type { AutoText } from '../types/Text';
3
- import { type NitroAction } from '../utils/NitroAction';
4
- import { type HeaderActions, Template, type TemplateConfig } from './Template';
5
- export interface NitroAutomotivePermissionRequestTemplateConfig extends TemplateConfig {
6
- headerActions?: Array<NitroAction>;
7
- title: AutoText;
8
- actions: Array<NitroAction>;
9
- }
10
- export type AutomotivePermissionRequestTemplateConfig = Omit<NitroAutomotivePermissionRequestTemplateConfig, 'headerActions' | 'buttons'> & {
11
- /**
12
- * action buttons, usually at the the top right on Android and a top bar on iOS
13
- */
14
- headerActions?: HeaderActions<AutomotivePermissionRequestTemplate>;
15
- actions: [CustomActionButtonAndroid<AutomotivePermissionRequestTemplate>] | [
16
- CustomActionButtonAndroid<AutomotivePermissionRequestTemplate>,
17
- CustomActionButtonAndroid<AutomotivePermissionRequestTemplate>
18
- ];
19
- };
20
- export declare class AutomotivePermissionRequestTemplate extends Template<AutomotivePermissionRequestTemplateConfig, HeaderActions<AutomotivePermissionRequestTemplate>> {
21
- private template;
22
- constructor(config: AutomotivePermissionRequestTemplateConfig);
23
- }
@@ -1,18 +0,0 @@
1
- import { NitroModules } from 'react-native-nitro-modules';
2
- import { NitroActionUtil } from '../utils/NitroAction';
3
- import { Template, } from './Template';
4
- const HybridAutomotivePermissionRequestTemplate = NitroModules.createHybridObject('AutomotivePermissionRequestTemplate');
5
- export class AutomotivePermissionRequestTemplate extends Template {
6
- template = this;
7
- constructor(config) {
8
- super(config);
9
- const { headerActions, actions, ...rest } = config;
10
- const nitroConfig = {
11
- ...rest,
12
- id: this.id,
13
- headerActions: NitroActionUtil.convert(this.template, headerActions),
14
- actions: NitroActionUtil.convert(this.template, actions),
15
- };
16
- HybridAutomotivePermissionRequestTemplate.createAutomotivePermissionRequestTemplate(nitroConfig);
17
- }
18
- }