Code Requirements
Code Requirements are best practices and code styles that shall be implemented in all FCA applications written for the R1 HU.
Application Code Requirements:
Android Version Kotlin Use V2C Global API Version Package Naming App Versioning Android Manifest Entries DRM Check sends AppManager intent VERIFY_DRM On Boot Complete UI Design Approach Full Screen Mode
The R1H and R1L platforms will be launching on the same Android version for each model year. All apps shall compile with the Android versions shown below.
| Model Year | Android Version |
|---|---|
| MY22 | Android O-MR1 (API level 27) |
| MY21 | Android O-MR1 (API level 27) |
SD.0A684 - FCA Signed Third Party Android Application Security Requirements Specification
[2.13.7] Second party applications shall be using approved languages for application development. For Android based telematics system/radio shall be using Java and may use C/C++ for native interface. Suppliers shall not use scripting languages like Javascript or Kotlin in their application.
V2C Global API are protocol buffers. Protocol Buffers are a method of serializing structured data. It is useful in developing programs to communicate with each other over a wire or for storing data. The method involves an interface description language that describes the structure of some data and a program that generates source code from that description for generating or parsing a stream of bytes that represents the structured data.
As of CAE API 1.3 the dependency on a specific version of protocol buffers has been removed.
Package names for all R1 apps shall be com.fca.uconnect.[app name].[app subpackage]. The package name shall be less than the 50 character limit imposed by the FCA SDP.
The following segments shall follow the Android application ID naming conventions found in the
Android Developer site at
Set the application ID.
[app name] is the application name and must be unique.
[app subpackage] is any sub package names the app requires.
The purpose of this versioning scheme is to track build dates as well as to provide a versioning scheme that always has a value that is greater than the previous by using the date. Multiple builds in a single day will be tracked by the revision, which uses a capital letter in English ascending alphabetical order.
For example: versionName "SR21-20-03-31-Rev.A"
The following app manifest entries are optional, but required to enable the behaviors described.
ShowConditions, deprecated, controls if an app will be made or not made visible in the App drawer based on the conditions listed. All conditions must be satisfied and the app must have UI to be shown in the apps list. If this entry is not present (default), the app will be visible in the App drawer.
Format:
Standard Value JSON Format:
Standard Value JSON Rules:
Standard Value Example:
PNET CAN Architecture: VC_VEH_LINE = 1(WK) or VC_VEH_LINE = 49(JL) and VC_SRT_PRSNT = 0 and VC_OffRoadPg = 1.
ATL Mid CAN Architecture: VC_VEH_LINE = 93(MP) and VC_SRT_PRSNT = 0 and VC_OffRoadPg = 1.
ATL High CAN Architecture: VC_VEH_LINE = 101(WL) and VC_SRT_PRSNT = 0 and VC_OffRoadPg = 1.
Special Value JSON Format:
Special Value Example:
InstallConditions, replaces ShowConditions and if present an app will be installed or not installed based on the conditions listed. All conditions must be satisfied for the app to be installed. If this entry is not present (default), the app will be installed.
If an app is not installed due to the install conditions, then AppManager will return an install condition error.
Until a new CAE API spec release, the integer error code shall be 14 as shown below.
public static final int ERROR_INSTALL_CONDITION = ERROR_CODE_BASE + 14;
Priv App Handling:
AppManager shall use "pm hide/unhide" on 2nd party apps which do not meet the "install criteria" but are installed under priv apps folder.
Example, assuming Alexa app should not show up under all regions. In that case, upon reading the app manifest file, AppManager will see that the app should not be "installed" and then run pm hide on the Alexa package.
Format:
Standard Value JSON Format:
Standard Value JSON Rules:
Standard Value Example 1
PNET CAN Architecture: VC_VEH_LINE = 35(WD) or VC_VEH_LINE = 49(LD) and VC_SRT_PRSNT = 1.
ATL Mid CAN Architecture: VC_VEH_LINE = 88(521) and VC_SRT_PRSNT = 1.
ATL High CAN Architecture: VC_VEH_LINE = 89(636VM) and VC_SRT_PRSNT = 1.
Standard Value Example 2
VC_VEH_LINE = RU and Hybrid_Type = PHEV
Special Value JSON Format:
Special Value Example:
Category, is optional and defines what tabbed views an app will be part of. The categories are defined in the HMI App Drawer Content document. The 1st cat in list is highlighted if multiple.
Example
VR Launch, is optional and allows the apps to give VR Names for different languages that the HU's support for use by the VR engine to start the app through VR.
The locales and Names are separated by a ":". Synonyms separated by commas (,) and locales are separated by semi colon (;).
Examples
All applications shall perform a DRM check as the first task in onCreate. The DRM check will verify the Digital Rights of the customer by sending AppManager intent VERIFY_DRM.
The verify DRM intent performs the following sequence of checks.
Uconnect® customer's must be registered and subscribe for Uconnect® features. If the customer is not registered and subscribed the app must terminate and start the In-Vehicle Activation (IVA)app.
If the DRM check fails for any reason other than not registered or subscribed the app must terminate.
You can download the intent definition found in AppManager on the Common Interfaces page.
The following code should be used for the DRM check. It can be downloaded
here
VerifyDRM Reference Code
.
private final int MAX_RETRY_VERIFY_DRM_TIMES = 3;
private final int WAIT_VERIFY_DRM_RESP_TIMEOUT = 500; // 500ms
private final int MSG_VERIFY_DRM_RESP = 1;
private final int MSG_VERIFY_DRM_TIMEOUT = 2;
private int mDrmVerifyResult = AppManager.RESULT_UNKNOWN;
/**
* Handler used for the verify DRM return message.
*/
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_VERIFY_DRM_RESP:
mHandler.removeMessages(MSG_VERIFY_DRM_TIMEOUT);
if (AppManager.RESULT_UNKNOWN == mDrmVerifyResult) {
handleVerifyDrmResult(msg);
} // else duplicated, ignore
break;
case MSG_VERIFY_DRM_TIMEOUT:
if (msg.arg1 < MAX_RETRY_VERIFY_DRM_TIMES) {
// send verify DRM broadcast again
verifyDrm(msg.arg1 + 1);
} else {
handleVerifyDrmTimeout();
}
break;
default:
break;
}
}
};
private Messenger mCallback = new Messenger(mHandler);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
verifyDrm(0);
}
/**
* verifyDRM sends the AppManager intent and sets up a time out method.
*
* @param seq is the sequence of calls to verifyDRM that is checked against the max
* count for retries. 1st call should always be zero.
*/
public void verifyDrm(int seq) {
Intent verifyDRMIntent = new Intent(AppManager.ACTION_VERIFY_DRM);
verifyDRMIntent.setPackage(AppManager.UCONNECT_SERVICE_PACKAGE);
verifyDRMIntent.putExtra(AppManager.EXTRA_REQUEST_CODE, MSG_VERIFY_DRM_RESP);
// The calling app package name must be entered here replacing "com.fca.uconnect.your app".
verifyDRMIntent.putExtra(android.content.Intent.EXTRA_PACKAGE_NAME, "com.fca.uconnect.yourapppackage");
verifyDRMIntent.putExtra(AppManager.EXTRA_CALLBACK, mCallback);
mAppContext.sendBroadcast(verifyDRMIntent);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_VERIFY_DRM_TIMEOUT, seq, 0),
WAIT_VERIFY_DRM_RESP_TIMEOUT);
}
/**
* Handles the returned verifyDRM message. This method will either terminate the app
* or allow it to run.
*
* @param msg returned from AppManager verifyDRM intent.
*/
private void handleVerifyDrmResult(Message msg) {
mDrmVerifyResult = msg.arg1;
// If verify DRM results are RESULT_OK then the app should continue running.
if (mDrmVerifyResult == AppManager.RESULT_NOK) {
// IVA will only handle Registration and Subscription.
if (msg.arg2 == AppManager.ERROR_VEH_NOT_REGISTERED || msg.arg2 == AppManager.ERROR_NO_ACTIVE_SUBSCRIPTION) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.fca.uconnect.iva", "com.fca.uconnect.iva.ExpiredConnectionActivity"));
if (intent != null) {
intent.putExtra(AppManager.ERROR_CODE, msg.arg2);
try {
startActivity(intent);
} catch (Exception e) {
// For some regions IVA will not be installed. The subscription in these regions is controlled
// using DRM. In these cases allow the app to run.
Log.d("VerifyDRM", "IVA is not availble, launch intent failed");
}
} else {
Log.d("VerifyDRM", "IVA is not availble, launch intent is null");
finish();
}
} else {
Log.d("VerifyDRM", "App failed DRM check with return code " + msg.arg2);
finish();
}
}
}
/**
* handleVerifyDrmTimeout is called after the max number of retries. There was no response from AppManager
* so the app must exit.
*/
private void handleVerifyDrmTimeout() {
Log.d("VerifyDRM","verify DRM timed out.");
finish();
}
Applications shall not use BOOT_COMPLETED broadcast to autostart.
The Android BOOT_COMPLETED broadcast is sent after the system has finished booting. At this point not all services are available to an app. Using this broadcast in a production app may cause thrashing.
The BOOT_COMPLETED broadcast can be used to test an app and should be removed after unit testing. See how to Auto Start and app.
UI design approach should use responsive layout design first, if unable to be responsive then map PDO template to HU size.
Responsive Layout Design guidance can be found at Constrain Layout, Screen Sizes and Responsive Layout
Hardcoded display size examples:
Display display = getWindowManager().getDefaultDisplay(); String displayName = display.getName(); // minSdkVersion=17+ // display size in pixels Point size = new Point(); display.getSize(size); int width = size.x; int height = size.y; // pixels, dpi DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); int heightPixels = metrics.heightPixels; int widthPixels = metrics.widthPixels; int densityDpi = metrics.densityDpi; float xdpi = metrics.xdpi; float ydpi = metrics.ydpi;
Applications shall not use full screen mode.
Full screen mode hides the status bar and shall not be used in our apps.
Updated: 09/21/2020, Android is a trademark of Google LLC