i18n P2: resourceize 361 hardcoded UI strings in 3 activities (en + zh-rCN)
- Replace UI literals with getString(R.string.*) across DiPlayActivity, CarPlayHostActivity, ImageCropActivity (316 keys + 15 parameterized keys) - Generate values/strings.xml (338 entries) and values-zh-rCN/strings.xml - Parameterize templates (SSID/version/suffix prefixes) with format args - Merge concatenated Android 9/MFi hint strings into single resources - Protect leading/trailing spaces via \\u0020 so AAPT does not trim them - Rename reserved resource name 'native' to 'resolution_native'
This commit is contained in:
1 parent
2b33c3de35
commit
9a4c03e2ec
5 files changed
+1026
-358
No files matched your search
@@ -160,7 +160,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
vpnReady = true
|
||||
maybeStartCarPlay()
|
||||
} else {
|
||||
setStatus("VPN consent was denied")
|
||||
setStatus(getString(R.string.vpn_consent_was_denied))
|
||||
}
|
||||
}
|
||||
private val wirelessPermissions =
|
||||
@@ -777,38 +777,38 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
isClickable = true
|
||||
}
|
||||
panel.addView(ImageView(this).apply {
|
||||
setImageResource(R.drawable.ic_carplay); contentDescription = "CarPlay"
|
||||
setImageResource(R.drawable.ic_carplay); contentDescription = getString(R.string.carplay)
|
||||
}, LinearLayout.LayoutParams(dp(88), dp(88)))
|
||||
panel.addView(TextView(this).apply {
|
||||
text = "DiPlay"; textSize = 34f; setTextColor(Color.rgb(241, 245, 252))
|
||||
text = getString(R.string.diplay); textSize = 34f; setTextColor(Color.rgb(241, 245, 252))
|
||||
gravity = Gravity.CENTER; setPadding(0, dp(18), 0, dp(14))
|
||||
typeface = Typeface.create("sans-serif-medium", Typeface.NORMAL)
|
||||
})
|
||||
val stage = TextView(this).apply {
|
||||
text = "Getting CarPlay ready…"; textSize = 22f; gravity = Gravity.CENTER
|
||||
text = getString(R.string.getting_carplay_ready); textSize = 22f; gravity = Gravity.CENTER
|
||||
setTextColor(Color.rgb(241, 245, 252))
|
||||
}
|
||||
panel.addView(stage)
|
||||
panel.addView(TextView(this).apply {
|
||||
text = if (wirelessEnabled) "Keep your iPhone nearby with Bluetooth and Wi-Fi on.\nAllow CarPlay if your iPhone asks."
|
||||
else "Use a USB data cable and unlock your iPhone.\nAllow Trust and CarPlay if your iPhone asks."
|
||||
text = if (wirelessEnabled) getString(R.string.keep_your_iphone_nearby_with_bluetooth_and_wi_fi_on_allow)
|
||||
else getString(R.string.use_a_usb_data_cable_and_unlock_your_iphone_allow_trust_an)
|
||||
textSize = 17f; gravity = Gravity.CENTER; setTextColor(Color.rgb(168, 182, 202))
|
||||
setPadding(0, dp(14), 0, dp(24))
|
||||
})
|
||||
panel.addView(Button(this).apply {
|
||||
text = "Reset CarPlay Wi-Fi"; isAllCaps = false; textSize = 18f
|
||||
text = getString(R.string.reset_carplay_wi_fi); isAllCaps = false; textSize = 18f
|
||||
visibility = View.GONE
|
||||
setOnClickListener { showDiPlayHome("wireless-recovery") }
|
||||
wifiRecoveryButton = this
|
||||
}, LinearLayout.LayoutParams(dp(300), dp(64)).apply { bottomMargin = dp(12) })
|
||||
panel.addView(Button(this).apply {
|
||||
text = "Back to DiPlay"; isAllCaps = false; textSize = 18f
|
||||
text = getString(R.string.back_to_diplay); isAllCaps = false; textSize = 18f
|
||||
setTextColor(Color.rgb(12, 17, 27))
|
||||
background = GradientDrawable().apply { setColor(Color.rgb(166, 200, 255)); cornerRadius = dp(20).toFloat() }
|
||||
setOnClickListener { showDiPlayHome() }
|
||||
}, LinearLayout.LayoutParams(dp(300), dp(64)))
|
||||
panel.addView(TextView(this).apply {
|
||||
text = "In CarPlay, swipe down with three fingers to open DiPlay settings."
|
||||
text = getString(R.string.in_carplay_swipe_down_with_three_fingers_to_open_diplay_se)
|
||||
textSize = 13f; gravity = Gravity.CENTER; setTextColor(Color.rgb(168, 182, 202)); setPadding(0, dp(20), 0, 0)
|
||||
})
|
||||
root.addView(panel, FrameLayout.LayoutParams(-1, -1))
|
||||
@@ -834,7 +834,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
setPadding(dp(48), dp(36), dp(48), dp(36))
|
||||
}
|
||||
content.addView(
|
||||
menuText("CarPlay settings", 32f, Color.WHITE, bold = true).apply {
|
||||
menuText(getString(R.string.carplay_settings), 32f, Color.WHITE, bold = true).apply {
|
||||
setPadding(dp(56), 0, 0, 0)
|
||||
},
|
||||
LinearLayout.LayoutParams(
|
||||
@@ -843,7 +843,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
),
|
||||
)
|
||||
content.addView(
|
||||
settingsCategoryHeader("Connection"),
|
||||
settingsCategoryHeader(getString(R.string.connection)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -863,12 +863,12 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
}
|
||||
wirelessRow.addView(
|
||||
menuText("Wireless CarPlay", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.wireless_carplay_2), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f),
|
||||
)
|
||||
val wirelessSwitch = Switch(this).apply {
|
||||
isChecked = wirelessEnabled
|
||||
contentDescription = "Wireless CarPlay transport"
|
||||
contentDescription = getString(R.string.wireless_carplay_transport)
|
||||
showText = false
|
||||
thumbTintList = ColorStateList(
|
||||
arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()),
|
||||
@@ -914,7 +914,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
content.addView(
|
||||
menuText("Hotspot status", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.hotspot_status), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -930,7 +930,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
content.addView(
|
||||
settingsCategoryHeader("Location"),
|
||||
settingsCategoryHeader(getString(R.string.location)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -945,7 +945,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
content.addView(
|
||||
settingsCategoryHeader("Startup"),
|
||||
settingsCategoryHeader(getString(R.string.startup)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -953,9 +953,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
content.addView(
|
||||
settingsSwitchRow(
|
||||
label = "Auto-start on boot",
|
||||
label = getString(R.string.auto_start_on_boot),
|
||||
checked = autoStartOnBoot,
|
||||
description = "Start CarPlay automatically after device boot",
|
||||
description = getString(R.string.start_carplay_automatically_after_device_boot),
|
||||
) { checked ->
|
||||
autoStartOnBoot = checked
|
||||
appendLog("Boot auto-start ${if (checked) "enabled" else "disabled"}")
|
||||
@@ -968,7 +968,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
if (advancedAudioChannelMappingSupported) {
|
||||
content.addView(
|
||||
settingsCategoryHeader("Audio"),
|
||||
settingsCategoryHeader(getString(R.string.audio)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -976,9 +976,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
content.addView(
|
||||
settingsSwitchRow(
|
||||
label = "Advanced audio channel mapping",
|
||||
label = getString(R.string.advanced_audio_channel_mapping),
|
||||
checked = advancedAudioChannelMapping,
|
||||
description = "Use usage / content-type routing instead of stream type",
|
||||
description = getString(R.string.use_usage_content_type_routing_instead_of_stream_type),
|
||||
) { checked ->
|
||||
advancedAudioChannelMapping = checked
|
||||
appendLog(
|
||||
@@ -995,7 +995,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
content.addView(
|
||||
settingsCategoryHeader("Identity & appearance"),
|
||||
settingsCategoryHeader(getString(R.string.identity_appearance)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1023,7 +1023,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
).apply { topMargin = dp(26) },
|
||||
)
|
||||
content.addView(
|
||||
settingsCategoryHeader("Display & video"),
|
||||
settingsCategoryHeader(getString(R.string.display_video)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1035,7 +1035,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
}
|
||||
resolutionHeader.addView(
|
||||
menuText("Resolution", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.resolution), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f),
|
||||
)
|
||||
val resolutionValue = menuText(
|
||||
@@ -1091,11 +1091,11 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.HORIZONTAL
|
||||
}
|
||||
range.addView(
|
||||
menuText("0.3x", 15f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.s_0_3x), 15f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f),
|
||||
)
|
||||
range.addView(
|
||||
menuText("1.0x", 15f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.s_1_0x), 15f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1111,7 +1111,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
content.addView(
|
||||
buildStepSliderSection(
|
||||
title = "Frame rate",
|
||||
title = getString(R.string.frame_rate),
|
||||
values = (
|
||||
AirPlayDisplaySettings.MIN_FPS..AirPlayDisplaySettings.MAX_FPS
|
||||
step AirPlayDisplaySettings.FPS_STEP
|
||||
@@ -1131,10 +1131,10 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
content.addView(
|
||||
settingsChoiceRow(
|
||||
label = "Physical size basis",
|
||||
label = getString(R.string.physical_size_basis),
|
||||
options = listOf(
|
||||
AirPlayPhysicalSizeBasis.WIDTH to "Widest width",
|
||||
AirPlayPhysicalSizeBasis.HEIGHT to "Longest height",
|
||||
AirPlayPhysicalSizeBasis.WIDTH to getString(R.string.widest_width),
|
||||
AirPlayPhysicalSizeBasis.HEIGHT to getString(R.string.longest_height),
|
||||
),
|
||||
selected = physicalSizeBasis,
|
||||
) { value ->
|
||||
@@ -1149,7 +1149,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
content.addView(
|
||||
buildStepSliderSection(
|
||||
title = "Physical length",
|
||||
title = getString(R.string.physical_length),
|
||||
values = (
|
||||
AirPlayDisplaySettings.MIN_WIDTH_PHYSICAL_MM..
|
||||
AirPlayDisplaySettings.MAX_WIDTH_PHYSICAL_MM
|
||||
@@ -1178,7 +1178,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
val hevcSwitch = Switch(this).apply {
|
||||
isChecked = hevcEnabled
|
||||
contentDescription = "HEVC H.265 video transport"
|
||||
contentDescription = getString(R.string.hevc_h_265_video_transport)
|
||||
showText = false
|
||||
thumbTintList = ColorStateList(
|
||||
arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()),
|
||||
@@ -1218,12 +1218,12 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
}
|
||||
softwareHevcRow.addView(
|
||||
menuText("HEVC software decoder", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.hevc_software_decoder), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f),
|
||||
)
|
||||
val softwareHevcSwitch = Switch(this).apply {
|
||||
isChecked = hevcSoftwareDecoderEnabled
|
||||
contentDescription = "Use software HEVC decoder"
|
||||
contentDescription = getString(R.string.use_software_hevc_decoder)
|
||||
showText = false
|
||||
thumbTintList = ColorStateList(
|
||||
arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()),
|
||||
@@ -1269,7 +1269,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
content.addView(
|
||||
settingsCategoryHeader("Window"),
|
||||
settingsCategoryHeader(getString(R.string.window)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1284,7 +1284,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
content.addView(
|
||||
settingsCategoryHeader("Diagnostics"),
|
||||
settingsCategoryHeader(getString(R.string.diagnostics)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1300,7 +1300,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
content.addView(
|
||||
settingsCategoryHeader("Android 9 compatibility"),
|
||||
settingsCategoryHeader(getString(R.string.android_9_compatibility)),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1308,10 +1308,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
content.addView(
|
||||
menuText(
|
||||
"The following settings are unavailable and hidden on Android 9 " +
|
||||
"(API 28):\n" +
|
||||
"• Wi-Fi P2P (5 GHz) — LocalOnlyHotspot is used instead.\n" +
|
||||
"• HEVC software decoder — hardware decoding is used instead.",
|
||||
getString(R.string.settings_android9_compat),
|
||||
16f,
|
||||
MENU_SECONDARY,
|
||||
),
|
||||
@@ -1332,7 +1329,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
val save = Button(this).apply {
|
||||
text = "Save and reconnect"
|
||||
text = getString(R.string.save_and_reconnect)
|
||||
isAllCaps = false
|
||||
textSize = 17f
|
||||
setTextColor(MENU_BUTTON_TEXT)
|
||||
@@ -1349,7 +1346,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
val exitApplicationButton = Button(this).apply {
|
||||
text = "EXIT APPLICATION"
|
||||
text = getString(R.string.exit_application)
|
||||
isAllCaps = false
|
||||
textSize = 17f
|
||||
setTextColor(Color.WHITE)
|
||||
@@ -1389,7 +1386,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
textSize = 22f
|
||||
setTextColor(Color.WHITE)
|
||||
backgroundTintList = ColorStateList.valueOf(MENU_TRACK_OFF)
|
||||
contentDescription = "Discard changes and exit settings"
|
||||
contentDescription = getString(R.string.discard_changes_and_exit_settings)
|
||||
minWidth = 0
|
||||
minHeight = 0
|
||||
setPadding(0, 0, 0, 0)
|
||||
@@ -1518,11 +1515,11 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
val targetChoice = settingsChoiceRow(
|
||||
label = "MFI certificate & signing target",
|
||||
label = getString(R.string.mfi_certificate_signing_target),
|
||||
options = listOf(
|
||||
MfiTarget.USB_CH341 to "USB/CH341",
|
||||
MfiTarget.I2C to "I2C",
|
||||
MfiTarget.REMOTE to "Remote",
|
||||
MfiTarget.USB_CH341 to getString(R.string.usb_ch341),
|
||||
MfiTarget.I2C to getString(R.string.i2c),
|
||||
MfiTarget.REMOTE to getString(R.string.remote),
|
||||
),
|
||||
selected = mfiTarget,
|
||||
) { target ->
|
||||
@@ -1544,7 +1541,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
addView(
|
||||
settingsInputRow(
|
||||
"I2C device",
|
||||
getString(R.string.i2c_device),
|
||||
mfiI2cPath,
|
||||
onInputCreated = { mfiI2cPathInput = it },
|
||||
) { value ->
|
||||
@@ -1557,7 +1554,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
),
|
||||
)
|
||||
addView(
|
||||
menuText("Linux device path, for example /dev/i2c-1.", 14f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.linux_device_path_for_example_dev_i2c_1), 14f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1577,7 +1574,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
addView(
|
||||
settingsInputRow(
|
||||
"Server address",
|
||||
getString(R.string.server_address),
|
||||
remoteMfiServer,
|
||||
onInputCreated = { remoteMfiServerInput = it },
|
||||
) { value ->
|
||||
@@ -1590,7 +1587,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
addView(
|
||||
settingsInputRow(
|
||||
"Token (optional)",
|
||||
getString(R.string.token_optional),
|
||||
remoteMfiToken,
|
||||
password = true,
|
||||
onInputCreated = { remoteMfiTokenInput = it },
|
||||
@@ -1604,8 +1601,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
addView(
|
||||
menuText(
|
||||
"Address must start with http:// or https://. Token is optional and sent " +
|
||||
"as an Authorization bearer token.",
|
||||
getString(R.string.settings_mfi_address_hint),
|
||||
14f,
|
||||
MENU_SECONDARY,
|
||||
),
|
||||
@@ -1665,10 +1661,10 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun mfiTargetLabel(target: MfiTarget): String = when (target) {
|
||||
MfiTarget.LOCAL -> "Local offline"
|
||||
MfiTarget.USB_CH341 -> "USB/CH341"
|
||||
MfiTarget.I2C -> "I2C"
|
||||
MfiTarget.REMOTE -> "Remote"
|
||||
MfiTarget.LOCAL -> getString(R.string.local_offline)
|
||||
MfiTarget.USB_CH341 -> getString(R.string.usb_ch341)
|
||||
MfiTarget.I2C -> getString(R.string.i2c)
|
||||
MfiTarget.REMOTE -> getString(R.string.remote)
|
||||
}
|
||||
|
||||
private fun buildIdentitySettingsSection(): View {
|
||||
@@ -1676,7 +1672,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
section.addView(
|
||||
settingsInputRow("Manufacturer", manufacturer) { value ->
|
||||
settingsInputRow(getString(R.string.manufacturer), manufacturer) { value ->
|
||||
manufacturer = value
|
||||
updateResolutionMenu()
|
||||
},
|
||||
@@ -1686,7 +1682,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
),
|
||||
)
|
||||
section.addView(
|
||||
settingsInputRow("Model", model) { value ->
|
||||
settingsInputRow(getString(R.string.model), model) { value ->
|
||||
model = value
|
||||
updateResolutionMenu()
|
||||
},
|
||||
@@ -1696,7 +1692,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
).apply { topMargin = dp(10) },
|
||||
)
|
||||
section.addView(
|
||||
settingsInputRow("OEM label", oemLabel) { value ->
|
||||
settingsInputRow(getString(R.string.oem_label), oemLabel) { value ->
|
||||
oemLabel = value
|
||||
updateResolutionMenu()
|
||||
},
|
||||
@@ -1719,12 +1715,12 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
gravity = Gravity.CENTER_VERTICAL
|
||||
}
|
||||
row.addView(
|
||||
menuText("Report location to iPhone", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.report_location_to_iphone), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f),
|
||||
)
|
||||
val switch = Switch(this@CarPlayHostActivity).apply {
|
||||
isChecked = locationReportingEnabled
|
||||
contentDescription = "Report Android location to the iPhone"
|
||||
contentDescription = getString(R.string.report_android_location_to_the_iphone)
|
||||
showText = false
|
||||
thumbTintList = ColorStateList(
|
||||
arrayOf(intArrayOf(android.R.attr.state_checked), intArrayOf()),
|
||||
@@ -1755,7 +1751,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
addView(
|
||||
menuText(
|
||||
"Sends precise Android location as CarPlay GPS data when the iPhone requests it.",
|
||||
getString(R.string.sends_precise_android_location_as_carplay_gps_data_when_th),
|
||||
14f,
|
||||
MENU_SECONDARY,
|
||||
),
|
||||
@@ -1781,9 +1777,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
private fun buildDebugLogsSection(): View =
|
||||
settingsSwitchRow(
|
||||
label = "Debug logs",
|
||||
label = getString(R.string.debug_logs),
|
||||
checked = debugLogsEnabled,
|
||||
description = "Show on-screen debug logs",
|
||||
description = getString(R.string.show_on_screen_debug_logs),
|
||||
) { checked ->
|
||||
debugLogsEnabled = checked
|
||||
appendLog("Debug logs ${if (debugLogsEnabled) "enabled" else "disabled"}")
|
||||
@@ -1860,7 +1856,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
section.addView(
|
||||
menuText("AirPlay icon", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.airplay_icon), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1887,7 +1883,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
actions.addView(
|
||||
Button(this).apply {
|
||||
text = "Choose image"
|
||||
text = getString(R.string.choose_image)
|
||||
isAllCaps = false
|
||||
setOnClickListener {
|
||||
externalActivityInProgress = true
|
||||
@@ -1901,7 +1897,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
actions.addView(
|
||||
Button(this).apply {
|
||||
text = "Default icon"
|
||||
text = getString(R.string.default_icon)
|
||||
isAllCaps = false
|
||||
setOnClickListener {
|
||||
AirPlayPersistence.clearCustomAirPlayIcon(this@CarPlayHostActivity)
|
||||
@@ -1947,7 +1943,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
section.addView(
|
||||
menuText("Driving side", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.driving_side), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1958,13 +1954,13 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
val left = RadioButton(this).apply {
|
||||
id = View.generateViewId()
|
||||
text = "Left-hand drive"
|
||||
text = getString(R.string.left_hand_drive)
|
||||
setTextColor(Color.WHITE)
|
||||
isChecked = !rightHandDrive
|
||||
}
|
||||
val right = RadioButton(this).apply {
|
||||
id = View.generateViewId()
|
||||
text = "Right-hand drive"
|
||||
text = getString(R.string.right_hand_drive)
|
||||
setTextColor(Color.WHITE)
|
||||
isChecked = rightHandDrive
|
||||
}
|
||||
@@ -1989,7 +1985,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
section.addView(
|
||||
menuText("Fullscreen", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.fullscreen), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -1997,9 +1993,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
section.addView(
|
||||
settingsSwitchRow(
|
||||
label = "Hide top bar",
|
||||
label = getString(R.string.hide_top_bar),
|
||||
checked = hideTopBar,
|
||||
description = "Hide the status bar",
|
||||
description = getString(R.string.hide_the_status_bar),
|
||||
) { checked ->
|
||||
hideTopBar = checked
|
||||
applyFullscreenMode()
|
||||
@@ -2012,9 +2008,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
section.addView(
|
||||
settingsSwitchRow(
|
||||
label = "Hide bottom bar",
|
||||
label = getString(R.string.hide_bottom_bar),
|
||||
checked = hideBottomBar,
|
||||
description = "Hide the navigation bar",
|
||||
description = getString(R.string.hide_the_navigation_bar),
|
||||
) { checked ->
|
||||
hideBottomBar = checked
|
||||
applyFullscreenMode()
|
||||
@@ -2033,7 +2029,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
section.addView(
|
||||
menuText("Safe area", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.safe_area), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -2052,7 +2048,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
buttons.addView(
|
||||
Button(this).apply {
|
||||
text = "Set"
|
||||
text = getString(R.string.set)
|
||||
isAllCaps = false
|
||||
setOnClickListener { openSafeAreaEditor() }
|
||||
},
|
||||
@@ -2060,7 +2056,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
buttons.addView(
|
||||
Button(this).apply {
|
||||
text = "Reset"
|
||||
text = getString(R.string.reset)
|
||||
isAllCaps = false
|
||||
setOnClickListener { resetSafeAreaForCurrentSize() }
|
||||
},
|
||||
@@ -2077,9 +2073,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
section.addView(
|
||||
settingsSwitchRow(
|
||||
label = "Draw outside safe area",
|
||||
label = getString(R.string.draw_outside_safe_area),
|
||||
checked = safeAreaDrawOutside,
|
||||
description = "Allow CarPlay UI outside the safe area",
|
||||
description = getString(R.string.allow_carplay_ui_outside_the_safe_area),
|
||||
) { checked ->
|
||||
safeAreaDrawOutside = checked
|
||||
updateResolutionMenu()
|
||||
@@ -2108,7 +2104,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
),
|
||||
)
|
||||
overlay.addView(
|
||||
menuText("Safe area", 24f, Color.WHITE, bold = true).apply {
|
||||
menuText(getString(R.string.safe_area), 24f, Color.WHITE, bold = true).apply {
|
||||
setPadding(dp(16), dp(12), dp(16), dp(8))
|
||||
},
|
||||
FrameLayout.LayoutParams(
|
||||
@@ -2124,7 +2120,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
controls.addView(
|
||||
Button(this).apply {
|
||||
text = "Cancel"
|
||||
text = getString(R.string.cancel)
|
||||
isAllCaps = false
|
||||
setOnClickListener { closeSafeAreaEditor() }
|
||||
},
|
||||
@@ -2132,7 +2128,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
controls.addView(
|
||||
Button(this).apply {
|
||||
text = "Save"
|
||||
text = getString(R.string.save)
|
||||
isAllCaps = false
|
||||
setOnClickListener { saveSafeAreaEditor() }
|
||||
},
|
||||
@@ -2258,7 +2254,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
section.addView(
|
||||
menuText("Wi-Fi session", 20f, MENU_SECONDARY),
|
||||
menuText(getString(R.string.wi_fi_session), 20f, MENU_SECONDARY),
|
||||
LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
@@ -2271,7 +2267,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
val modes = buildList {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
add(WirelessHotspotMode.WIFI_P2P to "Wi-Fi P2P (5 GHz)")
|
||||
add(WirelessHotspotMode.WIFI_P2P to getString(R.string.wi_fi_p2p_5_ghz))
|
||||
}
|
||||
add(WirelessHotspotMode.MANUAL to "Built-in car hotspot")
|
||||
}
|
||||
@@ -2325,7 +2321,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
orientation = LinearLayout.VERTICAL
|
||||
}
|
||||
manualFields.addView(
|
||||
settingsInputRow("Hotspot SSID", manualHotspotSsid) { value ->
|
||||
settingsInputRow(getString(R.string.hotspot_ssid), manualHotspotSsid) { value ->
|
||||
manualHotspotSsid = value
|
||||
manualHotspotErrorView?.visibility = View.GONE
|
||||
},
|
||||
@@ -2337,11 +2333,11 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
manualFields.addView(
|
||||
settingsChoiceRow(
|
||||
label = "Band",
|
||||
label = getString(R.string.band),
|
||||
options = listOf(
|
||||
ManualHotspotBand.AUTO to "Auto",
|
||||
ManualHotspotBand.GHZ_2_4 to "2.4 GHz",
|
||||
ManualHotspotBand.GHZ_5 to "5 GHz",
|
||||
ManualHotspotBand.AUTO to getString(R.string.auto),
|
||||
ManualHotspotBand.GHZ_2_4 to getString(R.string.s_2_4_ghz),
|
||||
ManualHotspotBand.GHZ_5 to getString(R.string.s_5_ghz),
|
||||
),
|
||||
selected = manualHotspotBand,
|
||||
) { value ->
|
||||
@@ -2356,7 +2352,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
manualFields.addView(
|
||||
settingsInputRow(
|
||||
label = "Channel (0 = auto)",
|
||||
label = getString(R.string.channel_0_auto),
|
||||
value = manualHotspotChannel.toString(),
|
||||
numeric = true,
|
||||
) { value ->
|
||||
@@ -2371,7 +2367,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
manualFields.addView(
|
||||
settingsInputRow(
|
||||
label = "Hotspot password",
|
||||
label = getString(R.string.hotspot_password),
|
||||
value = manualHotspotPassphrase,
|
||||
password = true,
|
||||
) { value ->
|
||||
@@ -2386,12 +2382,12 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
manualFields.addView(
|
||||
settingsChoiceRow(
|
||||
label = "Security",
|
||||
label = getString(R.string.security),
|
||||
options = listOf(
|
||||
ManualHotspotSecurity.OPEN to "Open",
|
||||
ManualHotspotSecurity.WPA2 to "WPA2",
|
||||
ManualHotspotSecurity.WPA3_TRANSITION to "WPA3 transition",
|
||||
ManualHotspotSecurity.WPA3 to "WPA3",
|
||||
ManualHotspotSecurity.OPEN to getString(R.string.open),
|
||||
ManualHotspotSecurity.WPA2 to getString(R.string.wpa2),
|
||||
ManualHotspotSecurity.WPA3_TRANSITION to getString(R.string.wpa3_transition),
|
||||
ManualHotspotSecurity.WPA3 to getString(R.string.wpa3),
|
||||
),
|
||||
selected = manualHotspotSecurity,
|
||||
) { value ->
|
||||
@@ -2437,16 +2433,16 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
private fun validateMfiSettings(): Boolean {
|
||||
val error = when {
|
||||
mfiTarget == MfiTarget.I2C && mfiI2cPath.isBlank() ->
|
||||
"I2C device path is required"
|
||||
getString(R.string.i2c_device_path_is_required)
|
||||
mfiTarget == MfiTarget.REMOTE && remoteMfiServer.isBlank() ->
|
||||
"Remote server address is required"
|
||||
getString(R.string.remote_server_address_is_required)
|
||||
mfiTarget == MfiTarget.REMOTE &&
|
||||
!remoteMfiServer.trim().startsWith("http://") &&
|
||||
!remoteMfiServer.trim().startsWith("https://") ->
|
||||
"Remote server address must start with http:// or https://"
|
||||
'\u0000' in mfiI2cPath -> "I2C device path contains U+0000"
|
||||
'\u0000' in remoteMfiServer -> "Remote server address contains U+0000"
|
||||
'\u0000' in remoteMfiToken -> "Remote token contains U+0000"
|
||||
getString(R.string.remote_server_address_must_start_with_http_or_https)
|
||||
'\u0000' in mfiI2cPath -> getString(R.string.i2c_device_path_contains_u_0000)
|
||||
'\u0000' in remoteMfiServer -> getString(R.string.remote_server_address_contains_u_0000)
|
||||
'\u0000' in remoteMfiToken -> getString(R.string.remote_token_contains_u_0000)
|
||||
else -> null
|
||||
}
|
||||
mfiErrorView?.text = error.orEmpty()
|
||||
@@ -2457,21 +2453,21 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
private fun validateManualHotspotSettings(): Boolean {
|
||||
if (wirelessHotspotMode != WirelessHotspotMode.MANUAL) return true
|
||||
val error = when {
|
||||
manualHotspotSsid.isBlank() -> "Hotspot SSID is required"
|
||||
manualHotspotSsid.isBlank() -> getString(R.string.hotspot_ssid_is_required)
|
||||
manualHotspotSsid.encodeToByteArray().size > 32 ->
|
||||
"Hotspot SSID must be at most 32 UTF-8 bytes"
|
||||
'\u0000' in manualHotspotSsid -> "Hotspot SSID contains U+0000"
|
||||
manualHotspotChannel !in 0..196 -> "Channel must be 0 or 1-196"
|
||||
getString(R.string.hotspot_ssid_must_be_at_most_32_utf_8_bytes)
|
||||
'\u0000' in manualHotspotSsid -> getString(R.string.hotspot_ssid_contains_u_0000)
|
||||
manualHotspotChannel !in 0..196 -> getString(R.string.channel_must_be_0_or_1_196)
|
||||
manualHotspotChannel != 0 &&
|
||||
!isManualHotspotChannelCompatible(manualHotspotBand, manualHotspotChannel) ->
|
||||
"Channel is not valid for the selected band"
|
||||
'\u0000' in manualHotspotPassphrase -> "Hotspot password contains U+0000"
|
||||
getString(R.string.channel_is_not_valid_for_the_selected_band)
|
||||
'\u0000' in manualHotspotPassphrase -> getString(R.string.hotspot_password_contains_u_0000)
|
||||
manualHotspotSecurity == ManualHotspotSecurity.OPEN &&
|
||||
manualHotspotPassphrase.isNotEmpty() ->
|
||||
"Password must be empty when security is Open"
|
||||
getString(R.string.password_must_be_empty_when_security_is_open)
|
||||
manualHotspotSecurity != ManualHotspotSecurity.OPEN &&
|
||||
manualHotspotPassphrase.length !in 8..63 ->
|
||||
"WPA2/WPA3 password must be 8-63 characters"
|
||||
getString(R.string.wpa2_wpa3_password_must_be_8_63_characters)
|
||||
else -> null
|
||||
}
|
||||
manualHotspotErrorView?.text = error.orEmpty()
|
||||
@@ -2480,9 +2476,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun hotspotModeLabel(mode: WirelessHotspotMode): String = when (mode) {
|
||||
WirelessHotspotMode.WIFI_P2P -> "Wi-Fi P2P (5 GHz)"
|
||||
WirelessHotspotMode.LOCAL_ONLY_HOTSPOT -> "LocalOnlyHotspot"
|
||||
WirelessHotspotMode.MANUAL -> "Manual hotspot"
|
||||
WirelessHotspotMode.WIFI_P2P -> getString(R.string.wi_fi_p2p_5_ghz)
|
||||
WirelessHotspotMode.LOCAL_ONLY_HOTSPOT -> getString(R.string.localonlyhotspot)
|
||||
WirelessHotspotMode.MANUAL -> getString(R.string.manual_hotspot)
|
||||
}
|
||||
|
||||
private fun menuText(
|
||||
@@ -2501,25 +2497,25 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
private fun updateHotspotStatus(status: CarPlayStatus) {
|
||||
if (!wirelessEnabled) return
|
||||
hotspotStatus = when (status) {
|
||||
CarPlayStatus.StartingHotspot -> HotspotStatus(state = "Starting")
|
||||
CarPlayStatus.StartingHotspot -> HotspotStatus(state = getString(R.string.starting))
|
||||
is CarPlayStatus.HotspotReady -> HotspotStatus(
|
||||
state = "Ready",
|
||||
state = getString(R.string.ready),
|
||||
ssid = status.ssid,
|
||||
band = status.band,
|
||||
channel = status.channel,
|
||||
backend = status.backend,
|
||||
)
|
||||
CarPlayStatus.WaitingForPairedIphone ->
|
||||
hotspotStatus.copy(state = "Waiting for paired iPhone")
|
||||
hotspotStatus.copy(state = getString(R.string.waiting_for_paired_iphone))
|
||||
CarPlayStatus.ConnectingBluetooth ->
|
||||
hotspotStatus.copy(state = "Connecting Bluetooth")
|
||||
hotspotStatus.copy(state = getString(R.string.connecting_bluetooth))
|
||||
CarPlayStatus.RunningWireless ->
|
||||
hotspotStatus.copy(state = "Running")
|
||||
hotspotStatus.copy(state = getString(R.string.running))
|
||||
CarPlayStatus.WirelessActive ->
|
||||
hotspotStatus.copy(state = "Active")
|
||||
hotspotStatus.copy(state = getString(R.string.active))
|
||||
CarPlayStatus.AttachingNetwork ->
|
||||
hotspotStatus.copy(state = "Starting AirPlay service")
|
||||
is CarPlayStatus.Failed -> hotspotStatus.copy(state = "Error")
|
||||
hotspotStatus.copy(state = getString(R.string.starting_airplay_service))
|
||||
is CarPlayStatus.Failed -> hotspotStatus.copy(state = getString(R.string.error))
|
||||
else -> return
|
||||
}
|
||||
updateHotspotStatusBlock()
|
||||
@@ -2527,7 +2523,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
|
||||
private fun updateHotspotStatusBlock() {
|
||||
if (!wirelessEnabled) {
|
||||
hotspotStatusView?.text = "Wireless hotspot: off"
|
||||
hotspotStatusView?.text = getString(R.string.wireless_hotspot_off)
|
||||
return
|
||||
}
|
||||
val status = hotspotStatus
|
||||
@@ -2602,7 +2598,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
resolutionValueView?.text = CarPlayDisplayScale.label(displayScaleTenths)
|
||||
val native = activeDisplaySize ?: currentActivitySize()
|
||||
val resolution = if (native == null) {
|
||||
"Handshake resolution: waiting for display"
|
||||
getString(R.string.handshake_resolution_waiting_for_display)
|
||||
} else {
|
||||
val negotiated = CarPlayDisplayScale.apply(
|
||||
AirPlayDisplayConfig(
|
||||
@@ -2613,7 +2609,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
),
|
||||
displayScaleTenths,
|
||||
)
|
||||
"Handshake resolution: ${native.width} x ${native.height} -> " +
|
||||
"${getString(R.string.resolution_handshake_prefix)}${native.width} x ${native.height} -> " +
|
||||
"${negotiated.widthPixels} x ${negotiated.heightPixels}"
|
||||
}
|
||||
val transport = if (!hevcEnabled) {
|
||||
@@ -2727,7 +2723,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
appendLog("Larger CarPlay canvas unavailable reason=${support.reason}; using Default icon and text size")
|
||||
runOnUiThread {
|
||||
android.widget.Toast.makeText(this,
|
||||
"This head unit cannot use the smaller size at this resolution. Using Default.",
|
||||
getString(R.string.this_head_unit_cannot_use_the_smaller_size_at_this_resolut),
|
||||
android.widget.Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
@@ -2814,7 +2810,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
val bitmap = customBitmap ?: BitmapFactory.decodeResource(resources, R.raw.placeholder_icon)
|
||||
preview.setImageBitmap(bitmap)
|
||||
iconStatusView?.text =
|
||||
if (customBitmap != null) "Custom 1:1 icon" else "Default placeholder icon"
|
||||
if (customBitmap != null) getString(R.string.custom_1_1_icon) else getString(R.string.default_placeholder_icon)
|
||||
}
|
||||
|
||||
private fun currentActivitySize(): DisplaySize? {
|
||||
@@ -2836,12 +2832,12 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
|
||||
private fun safeAreaSummary(): String {
|
||||
val size = currentActivitySize() ?: return "Safe area: waiting for activity size"
|
||||
val size = currentActivitySize() ?: return getString(R.string.safe_area_waiting_for_activity_size)
|
||||
val mapping = AirPlayPersistence.loadSafeAreaRect(this, size.width, size.height)
|
||||
return if (mapping == null) {
|
||||
"Safe area: full screen at ${size.width} x ${size.height}"
|
||||
"${getString(R.string.safe_area_full_screen_at)}${size.width} x ${size.height}"
|
||||
} else {
|
||||
"Safe area: ${mapping.width} x ${mapping.height} at " +
|
||||
"${getString(R.string.safe_area_prefix)}${mapping.width} x ${mapping.height} at " +
|
||||
"(${mapping.left}, ${mapping.top}) in ${size.width} x ${size.height}"
|
||||
}
|
||||
}
|
||||
@@ -2973,7 +2969,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
return@runOnUiThread
|
||||
}
|
||||
activeScreenStreamTypes.clear()
|
||||
setConnectionStage("CarPlay session ended; reconnecting")
|
||||
setConnectionStage(getString(R.string.carplay_session_ended_reconnecting))
|
||||
appendLog("AirPlay session ended; reconnecting from scratch")
|
||||
reconnectAfterLoss("AirPlay session ended")
|
||||
}
|
||||
@@ -2985,7 +2981,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
return@runOnUiThread
|
||||
}
|
||||
activeScreenStreamTypes.clear()
|
||||
setConnectionStage("Transport error; reconnecting")
|
||||
setConnectionStage(getString(R.string.transport_error_reconnecting))
|
||||
appendLog("CarPlay transport error: $message; reconnecting from scratch")
|
||||
reconnectAfterLoss("CarPlay transport error: $message")
|
||||
}
|
||||
@@ -3064,9 +3060,9 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
)
|
||||
setConnectionStage(
|
||||
if (serviceReused) {
|
||||
"CarPlay service already running"
|
||||
getString(R.string.carplay_service_already_running)
|
||||
} else {
|
||||
"CarPlay session already running"
|
||||
getString(R.string.carplay_session_already_running)
|
||||
},
|
||||
)
|
||||
updateDebugOverlays()
|
||||
@@ -3147,7 +3143,7 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
} catch (error: RuntimeException) {
|
||||
appendLog("Connection could not start: ${error.javaClass.simpleName}")
|
||||
shutdown(false, "foreground service could not start")
|
||||
setConnectionStage("Could not start CarPlay. Return to DiPlay and check app permissions.")
|
||||
setConnectionStage(getString(R.string.could_not_start_carplay_return_to_diplay_and_check_app_per))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3489,21 +3485,21 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun friendlyStage(message: String): String = when {
|
||||
message.contains("Turn on Wi-Fi", true) -> "Turn on Wi-Fi in the head unit’s settings to connect."
|
||||
message.contains("Allow precise Location", true) -> "Allow precise Location for DiPlay in the head unit’s app permissions."
|
||||
message.contains("Allow Nearby devices", true) -> "Allow Nearby devices for DiPlay in the head unit’s app permissions."
|
||||
message.contains("createGroup failed", true) -> "The head unit couldn’t start CarPlay Wi-Fi. Check Wi-Fi and close other projection apps. Retrying…"
|
||||
message.contains("needs a reset", true) -> "A previous Wi-Fi Direct connection is still running. Reset it to connect."
|
||||
message.contains("socket", true) || message.contains("RFCOMM", true) -> "Your iPhone isn’t available. Unlock it and check Bluetooth."
|
||||
message.contains("unsupported", true) || message.contains("not supported", true) -> "This head unit may not support wireless CarPlay. Try a USB connection."
|
||||
message.contains("denied", true) || message.contains("permission", true) -> "Allow the connection permission to continue"
|
||||
message.contains("Failed", true) || message.contains("error", true) -> "Connection interrupted. Retrying…"
|
||||
message.contains("Waiting for iPhone", true) || message.contains("Discovering iPhone", true) -> "Connect your iPhone with a USB cable"
|
||||
message.contains("paired", true) -> "Looking for your paired iPhone…"
|
||||
message.contains("Bluetooth", true) -> "Connecting to your iPhone…"
|
||||
message.contains("reconnect", true) || message.contains("ended", true) -> "Reconnecting to your iPhone…"
|
||||
message.contains("active", true) || message.contains("running", true) -> "Opening CarPlay…"
|
||||
else -> "Getting CarPlay ready…"
|
||||
message.contains("Turn on Wi-Fi", true) -> getString(R.string.turn_on_wi_fi_in_the_head_unit_s_settings_to_connect)
|
||||
message.contains("Allow precise Location", true) -> getString(R.string.allow_precise_location_for_diplay_in_the_head_unit_s_app_p)
|
||||
message.contains("Allow Nearby devices", true) -> getString(R.string.allow_nearby_devices_for_diplay_in_the_head_unit_s_app_per)
|
||||
message.contains("createGroup failed", true) -> getString(R.string.the_head_unit_couldn_t_start_carplay_wi_fi_check_wi_fi_and)
|
||||
message.contains("needs a reset", true) -> getString(R.string.a_previous_wi_fi_direct_connection_is_still_running_reset)
|
||||
message.contains("socket", true) || message.contains("RFCOMM", true) -> getString(R.string.your_iphone_isn_t_available_unlock_it_and_check_bluetooth)
|
||||
message.contains("unsupported", true) || message.contains("not supported", true) -> getString(R.string.this_head_unit_may_not_support_wireless_carplay_try_a_usb)
|
||||
message.contains("denied", true) || message.contains("permission", true) -> getString(R.string.allow_the_connection_permission_to_continue)
|
||||
message.contains("Failed", true) || message.contains("error", true) -> getString(R.string.connection_interrupted_retrying)
|
||||
message.contains("Waiting for iPhone", true) || message.contains("Discovering iPhone", true) -> getString(R.string.connect_your_iphone_with_a_usb_cable)
|
||||
message.contains("paired", true) -> getString(R.string.looking_for_your_paired_iphone)
|
||||
message.contains("Bluetooth", true) -> getString(R.string.connecting_to_your_iphone)
|
||||
message.contains("reconnect", true) || message.contains("ended", true) -> getString(R.string.reconnecting_to_your_iphone)
|
||||
message.contains("active", true) || message.contains("running", true) -> getString(R.string.opening_carplay)
|
||||
else -> getString(R.string.getting_carplay_ready)
|
||||
}
|
||||
|
||||
private fun appendLog(message: String) {
|
||||
@@ -3575,30 +3571,30 @@ class CarPlayHostActivity : ComponentActivity() {
|
||||
private fun dp(value: Int): Int = (value * resources.displayMetrics.density).toInt()
|
||||
|
||||
private fun CarPlayStatus.describe(): String = when (this) {
|
||||
CarPlayStatus.DiscoveringMfi -> "Preparing MFi authentication"
|
||||
CarPlayStatus.WaitingForMfi -> "Waiting for MFi coprocessor"
|
||||
CarPlayStatus.RequestingMfiPermission -> "Requesting MFi USB permission"
|
||||
CarPlayStatus.MfiReady -> "MFi authentication ready"
|
||||
CarPlayStatus.StartingHotspot -> "Starting wireless hotspot"
|
||||
CarPlayStatus.DiscoveringMfi -> getString(R.string.preparing_mfi_authentication)
|
||||
CarPlayStatus.WaitingForMfi -> getString(R.string.waiting_for_mfi_coprocessor)
|
||||
CarPlayStatus.RequestingMfiPermission -> getString(R.string.requesting_mfi_usb_permission)
|
||||
CarPlayStatus.MfiReady -> getString(R.string.mfi_authentication_ready)
|
||||
CarPlayStatus.StartingHotspot -> getString(R.string.starting_wireless_hotspot)
|
||||
is CarPlayStatus.HotspotReady ->
|
||||
"Hotspot ready: $backend, $ssid, $band, " +
|
||||
"channel ${if (channel == 0) "auto" else channel}"
|
||||
CarPlayStatus.WaitingForPairedIphone -> "Waiting for paired iPhone"
|
||||
CarPlayStatus.ConnectingBluetooth -> "Connecting Bluetooth"
|
||||
CarPlayStatus.RunningWireless -> "Wireless CarPlay control running"
|
||||
CarPlayStatus.WirelessActive -> "Wireless CarPlay active"
|
||||
CarPlayStatus.DiscoveringIphone -> "Discovering iPhone"
|
||||
CarPlayStatus.WaitingForIphone -> "Waiting for iPhone over USB"
|
||||
CarPlayStatus.RequestingIphonePermission -> "Requesting iPhone USB permission"
|
||||
CarPlayStatus.WaitingForPairedIphone -> getString(R.string.waiting_for_paired_iphone)
|
||||
CarPlayStatus.ConnectingBluetooth -> getString(R.string.connecting_bluetooth)
|
||||
CarPlayStatus.RunningWireless -> getString(R.string.wireless_carplay_control_running)
|
||||
CarPlayStatus.WirelessActive -> getString(R.string.wireless_carplay_active)
|
||||
CarPlayStatus.DiscoveringIphone -> getString(R.string.discovering_iphone)
|
||||
CarPlayStatus.WaitingForIphone -> getString(R.string.waiting_for_iphone_over_usb)
|
||||
CarPlayStatus.RequestingIphonePermission -> getString(R.string.requesting_iphone_usb_permission)
|
||||
CarPlayStatus.WaitingForReenumeration -> "Waiting for iPhone re-enumeration"
|
||||
CarPlayStatus.SelectingConfiguration -> "Selecting CarPlay configuration"
|
||||
CarPlayStatus.OpeningDataPaths -> "Opening USB data paths"
|
||||
CarPlayStatus.Pairing -> "Pairing with iPhone"
|
||||
CarPlayStatus.ConnectingControl -> "Connecting iAP2 control"
|
||||
CarPlayStatus.SelectingConfiguration -> getString(R.string.selecting_carplay_configuration)
|
||||
CarPlayStatus.OpeningDataPaths -> getString(R.string.opening_usb_data_paths)
|
||||
CarPlayStatus.Pairing -> getString(R.string.pairing_with_iphone)
|
||||
CarPlayStatus.ConnectingControl -> getString(R.string.connecting_iap2_control)
|
||||
CarPlayStatus.AttachingNetwork ->
|
||||
if (wirelessEnabled) "Starting AirPlay service" else "Attaching NCM/AirPlay network"
|
||||
CarPlayStatus.RunningControl -> "CarPlay control running"
|
||||
CarPlayStatus.ControlEnded -> "CarPlay control window ended"
|
||||
if (wirelessEnabled) getString(R.string.starting_airplay_service) else "Attaching NCM/AirPlay network"
|
||||
CarPlayStatus.RunningControl -> getString(R.string.carplay_control_running)
|
||||
CarPlayStatus.ControlEnded -> getString(R.string.carplay_control_window_ended)
|
||||
is CarPlayStatus.Failed -> "Failed: ${message}"
|
||||
}
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
override fun run() { refreshStatus(); handler.postDelayed(this, 1000) }
|
||||
}
|
||||
private val bluetoothPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
|
||||
if (granted) choosePhone() else permissionHelp("Nearby devices", "Allow Nearby devices so DiPlay can connect to your paired iPhone.")
|
||||
if (granted) choosePhone() else permissionHelp(getString(R.string.nearby_devices), getString(R.string.allow_nearby_devices_so_diplay_can_connect_to_your_paired))
|
||||
}
|
||||
private val export = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
|
||||
if (uri != null) exportDiagnostics(uri)
|
||||
@@ -127,9 +127,9 @@ class DiPlayActivity : ComponentActivity() {
|
||||
val content = column().apply { setPadding(dp(32), dp(24), dp(32), dp(32)) }
|
||||
scroll.addView(content)
|
||||
val header = row().apply { gravity = Gravity.CENTER_VERTICAL }
|
||||
header.addView(ImageView(this).apply { setImageResource(R.drawable.ic_carplay); contentDescription = "CarPlay" }, LinearLayout.LayoutParams(dp(36), dp(36)))
|
||||
header.addView(label("DiPlay", 26, TEXT, true).apply { setPadding(dp(12), 0, 0, 0) }, LinearLayout.LayoutParams(0, dp(56), 1f))
|
||||
header.addView(button(if (page == "home") "Car home" else "Back", false) {
|
||||
header.addView(ImageView(this).apply { setImageResource(R.drawable.ic_carplay); contentDescription = getString(R.string.carplay) }, LinearLayout.LayoutParams(dp(36), dp(36)))
|
||||
header.addView(label(getString(R.string.diplay), 26, TEXT, true).apply { setPadding(dp(12), 0, 0, 0) }, LinearLayout.LayoutParams(0, dp(56), 1f))
|
||||
header.addView(button(if (page == "home") getString(R.string.car_home) else getString(R.string.back), false) {
|
||||
if (page == "home") startActivity(Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME))
|
||||
else { page = "home"; render() }
|
||||
}, LinearLayout.LayoutParams(dp(130), dp(56)))
|
||||
@@ -149,14 +149,14 @@ class DiPlayActivity : ComponentActivity() {
|
||||
val wide = resources.configuration.screenWidthDp >= 850
|
||||
val body = column()
|
||||
val left = column()
|
||||
left.addView(label("YOUR PHONE. YOUR DRIVE.", 12, ACCENT, true).apply { letterSpacing = .16f })
|
||||
left.addView(label("A familiar drive.", if (wide) 42 else 36, TEXT, true).apply { setPadding(0, dp(12), 0, dp(10)) })
|
||||
left.addView(label("Your maps, music and conversations.\nCarPlay, right here on your car display.", 19, MUTED))
|
||||
left.addView(label(getString(R.string.your_phone_your_drive), 12, ACCENT, true).apply { letterSpacing = .16f })
|
||||
left.addView(label(getString(R.string.a_familiar_drive), if (wide) 42 else 36, TEXT, true).apply { setPadding(0, dp(12), 0, dp(10)) })
|
||||
left.addView(label(getString(R.string.your_maps_music_and_conversations_carplay_right_here_on_yo), 19, MUTED))
|
||||
val card = card()
|
||||
card.addView(label("WIRELESS CARPLAY", 12, ACCENT, true).apply { letterSpacing = .12f })
|
||||
status = label("Ready when you are", 24, TEXT, true).apply { setPadding(0, dp(10), 0, dp(16)) }
|
||||
card.addView(label(getString(R.string.wireless_carplay), 12, ACCENT, true).apply { letterSpacing = .12f })
|
||||
status = label(getString(R.string.ready_when_you_are), 24, TEXT, true).apply { setPadding(0, dp(10), 0, dp(16)) }
|
||||
card.addView(status)
|
||||
connectButton = button("Connect phone", true) {
|
||||
connectButton = button(getString(R.string.connect_phone), true) {
|
||||
if (CarPlayBackgroundSession.hasSession()) openProjection()
|
||||
else connect(true)
|
||||
}
|
||||
@@ -168,11 +168,11 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
card.addView(label(connectionHint, 15, MUTED).apply { setPadding(0, dp(14), 0, 0) })
|
||||
if (carHotspotOff()) {
|
||||
card.addView(label("The car hotspot “${AirPlayPersistence.loadManualHotspotSsid(this)}” is off. Turn it on in the car settings before connecting.", 15, WARNING).apply { setPadding(0, dp(14), 0, 0) })
|
||||
card.addView(button("Open car hotspot settings", false) { openCarWifiSettings() }, matchButton(10, 56))
|
||||
card.addView(label(getString(R.string.msg_car_hotspot_off, AirPlayPersistence.loadManualHotspotSsid(this)), 15, WARNING).apply { setPadding(0, dp(14), 0, 0) })
|
||||
card.addView(button(getString(R.string.open_car_hotspot_settings), false) { openCarWifiSettings() }, matchButton(10, 56))
|
||||
}
|
||||
card.addView(button("Choose iPhone", false) { choosePhone() }, matchButton(16, 56))
|
||||
disconnectButton = button("Disconnect", false) {
|
||||
card.addView(button(getString(R.string.choose_iphone), false) { choosePhone() }, matchButton(16, 56))
|
||||
disconnectButton = button(getString(R.string.disconnect), false) {
|
||||
disconnectButton?.isEnabled = false
|
||||
CarPlayBackgroundSession.stop { runOnUiThread { refreshStatus() } }
|
||||
}.apply { visibility = View.GONE }
|
||||
@@ -180,18 +180,18 @@ class DiPlayActivity : ComponentActivity() {
|
||||
val right = column().apply { gravity = Gravity.CENTER_HORIZONTAL }
|
||||
val logo = ImageView(this).apply {
|
||||
setImageResource(R.drawable.ic_carplay)
|
||||
contentDescription = "CarPlay icon"
|
||||
contentDescription = getString(R.string.carplay_icon)
|
||||
scaleType = ImageView.ScaleType.FIT_CENTER
|
||||
}
|
||||
val branding = column().apply {
|
||||
gravity = Gravity.CENTER
|
||||
addView(logo, LinearLayout.LayoutParams(dp(96), dp(96)))
|
||||
}
|
||||
right.addView(button("Connect with USB", false) { connect(false) }, matchButton())
|
||||
right.addView(label("Plug your iPhone into a USB data port.\nAllow CarPlay when your iPhone asks.", 14, MUTED).apply { gravity = Gravity.CENTER; setPadding(dp(8), dp(10), dp(8), dp(24)) })
|
||||
right.addView(button("Settings", false) { page = "settings"; render() }, matchButton())
|
||||
right.addView(label("Make DiPlay feel right for your car.", 14, MUTED).apply { gravity = Gravity.CENTER; setPadding(0, dp(10), 0, dp(24)) })
|
||||
right.addView(label("PUBLIC PREVIEW · ${version()}", 12, MUTED).apply { letterSpacing = .08f })
|
||||
right.addView(button(getString(R.string.connect_with_usb), false) { connect(false) }, matchButton())
|
||||
right.addView(label(getString(R.string.plug_your_iphone_into_a_usb_data_port_allow_carplay_when_y), 14, MUTED).apply { gravity = Gravity.CENTER; setPadding(dp(8), dp(10), dp(8), dp(24)) })
|
||||
right.addView(button(getString(R.string.settings), false) { page = "settings"; render() }, matchButton())
|
||||
right.addView(label(getString(R.string.make_diplay_feel_right_for_your_car), 14, MUTED).apply { gravity = Gravity.CENTER; setPadding(0, dp(10), 0, dp(24)) })
|
||||
right.addView(label("${getString(R.string.home_public_preview)}${version()}", 12, MUTED).apply { letterSpacing = .08f })
|
||||
if (wide) {
|
||||
// Both rows share column widths. The USB button starts at the wireless
|
||||
// card's top edge, independently of hero wrapping or font scaling.
|
||||
@@ -218,50 +218,50 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun settings(content: LinearLayout) {
|
||||
content.addView(label("Your drive, your way.", 34, TEXT, true))
|
||||
content.addView(label("Apply reconnects CarPlay for size, resolution, music buffer and frame rate. Other changes apply to your next connection.", 17, MUTED).apply { setPadding(0, dp(8), 0, dp(24)) })
|
||||
content.addView(label(getString(R.string.your_drive_your_way), 34, TEXT, true))
|
||||
content.addView(label(getString(R.string.apply_reconnects_carplay_for_size_resolution_music_buffer), 17, MUTED).apply { setPadding(0, dp(8), 0, dp(24)) })
|
||||
languageSettings(content)
|
||||
section(content, "Connection setup", R.drawable.ic_dp_connection) { card ->
|
||||
card.addView(label("Choose how to connect, follow the setup steps and save your car hotspot details.", 16, MUTED))
|
||||
card.addView(button("Open connection setup", false) { page = "connection"; render() }, matchButton(12, 60))
|
||||
section(content, getString(R.string.connection_setup), R.drawable.ic_dp_connection) { card ->
|
||||
card.addView(label(getString(R.string.choose_how_to_connect_follow_the_setup_steps_and_save_your), 16, MUTED))
|
||||
card.addView(button(getString(R.string.open_connection_setup), false) { page = "connection"; render() }, matchButton(12, 60))
|
||||
}
|
||||
section(content, "Diagnostics", R.drawable.ic_dp_diagnostics) { card ->
|
||||
exportButton = button(if (exportInProgress) "Saving report…" else "Save diagnostic report", false) {
|
||||
section(content, getString(R.string.diagnostics), R.drawable.ic_dp_diagnostics) { card ->
|
||||
exportButton = button(if (exportInProgress) getString(R.string.saving_report) else getString(R.string.save_diagnostic_report), false) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) exportDiagnostics()
|
||||
else chooseReportDestination()
|
||||
}.apply { isEnabled = !exportInProgress }
|
||||
card.addView(exportButton, matchButton(10, 60))
|
||||
card.addView(button("Choose save location", false) { chooseReportDestination() }, matchButton(10, 60))
|
||||
val destination = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) "Reports save to Downloads/DiPlay. " else "Choose where to save your report. "
|
||||
card.addView(label(destination + "Nothing is sent automatically. Protocol payloads and credentials are excluded.", 14, MUTED).apply { setPadding(0, dp(12), 0, 0) })
|
||||
card.addView(button(getString(R.string.choose_save_location), false) { chooseReportDestination() }, matchButton(10, 60))
|
||||
val destination = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) getString(R.string.reports_save_to_downloads_diplay) else getString(R.string.choose_where_to_save_your_report)
|
||||
card.addView(label(destination + getString(R.string.nothing_is_sent_automatically_protocol_payloads_and_creden), 14, MUTED).apply { setPadding(0, dp(12), 0, 0) })
|
||||
}
|
||||
section(content, "Automatic connection", R.drawable.ic_dp_automation) { card ->
|
||||
toggle(card, "Connect when DiPlay opens", "Use your last connection type and selected iPhone.", DiPlayPreferences.autoConnect(this)) { DiPlayPreferences.saveAutoConnect(this, it) }
|
||||
toggle(card, "Open after the car starts", "Availability depends on your head unit’s startup settings.", AirPlayPersistence.loadAutoStartOnBoot(this)) { AirPlayPersistence.saveAutoStartOnBoot(this, it) }
|
||||
card.addView(button("Choose iPhone · ${DiPlayPreferences.phoneName(this)}", false) { choosePhone() }, matchButton(12, 60))
|
||||
section(content, getString(R.string.automatic_connection), R.drawable.ic_dp_automation) { card ->
|
||||
toggle(card, getString(R.string.connect_when_diplay_opens), getString(R.string.use_your_last_connection_type_and_selected_iphone), DiPlayPreferences.autoConnect(this)) { DiPlayPreferences.saveAutoConnect(this, it) }
|
||||
toggle(card, getString(R.string.open_after_the_car_starts), getString(R.string.availability_depends_on_your_head_unit_s_startup_settings), AirPlayPersistence.loadAutoStartOnBoot(this)) { AirPlayPersistence.saveAutoStartOnBoot(this, it) }
|
||||
card.addView(button("${getString(R.string.choose_iphone_prefix)}${DiPlayPreferences.phoneName(this)}", false) { choosePhone() }, matchButton(12, 60))
|
||||
}
|
||||
section(content, "Display and performance", R.drawable.ic_dp_display) { card ->
|
||||
section(content, getString(R.string.display_and_performance), R.drawable.ic_dp_display) { card ->
|
||||
carPlaySizeControl(card)
|
||||
choice(card, "Resolution", listOf("Native", "80% · lighter load", "60% · lightest load"), listOf(10, 8, 6).indexOf(AirPlayPersistence.loadDisplayScaleTenths(this)).coerceAtLeast(0)) { AirPlayPersistence.saveDisplayScaleTenths(this, listOf(10, 8, 6)[it]) }
|
||||
choice(card, getString(R.string.resolution), listOf(getString(R.string.resolution_native), getString(R.string.s_80_lighter_load), getString(R.string.s_60_lightest_load)), listOf(10, 8, 6).indexOf(AirPlayPersistence.loadDisplayScaleTenths(this)).coerceAtLeast(0)) { AirPlayPersistence.saveDisplayScaleTenths(this, listOf(10, 8, 6)[it]) }
|
||||
val bufferPresets = com.shilapi.xcertplay.media.MediaAudioBuffer.presets
|
||||
choice(card, "Music buffer", listOf("300 ms · default", "500 ms", "1000 ms · most stable"),
|
||||
choice(card, getString(R.string.music_buffer), listOf(getString(R.string.s_300_ms_default), getString(R.string.s_500_ms), getString(R.string.s_1000_ms_most_stable)),
|
||||
bufferPresets.indexOf(AirPlayPersistence.loadMediaBufferMillis(this)).coerceAtLeast(0)) {
|
||||
AirPlayPersistence.saveMediaBufferMillis(this, bufferPresets[it])
|
||||
}
|
||||
choice(card, "Frame rate", listOf("30 fps · lighter load", "60 fps · smoother motion"), if (AirPlayPersistence.loadFps(this) == 60) 1 else 0) { AirPlayPersistence.saveFps(this, if (it == 1) 60 else 30) }
|
||||
toggle(card, "Efficient video", "Use HEVC. Leave off for the widest head-unit compatibility.", AirPlayPersistence.loadHevcEnabled(this)) { AirPlayPersistence.saveHevcEnabled(this, it) }
|
||||
toggle(card, "Right-hand drive", "Place CarPlay’s controls closer to the driver.", AirPlayPersistence.loadRightHandDrive(this)) { AirPlayPersistence.saveRightHandDrive(this, it) }
|
||||
toggle(card, "Full screen", "Hide the car’s system bars while CarPlay is open.", AirPlayPersistence.loadHideTopBar(this) && AirPlayPersistence.loadHideBottomBar(this)) {
|
||||
choice(card, getString(R.string.frame_rate), listOf(getString(R.string.s_30_fps_lighter_load), getString(R.string.s_60_fps_smoother_motion)), if (AirPlayPersistence.loadFps(this) == 60) 1 else 0) { AirPlayPersistence.saveFps(this, if (it == 1) 60 else 30) }
|
||||
toggle(card, getString(R.string.efficient_video), getString(R.string.use_hevc_leave_off_for_the_widest_head_unit_compatibility), AirPlayPersistence.loadHevcEnabled(this)) { AirPlayPersistence.saveHevcEnabled(this, it) }
|
||||
toggle(card, getString(R.string.right_hand_drive), getString(R.string.place_carplay_s_controls_closer_to_the_driver), AirPlayPersistence.loadRightHandDrive(this)) { AirPlayPersistence.saveRightHandDrive(this, it) }
|
||||
toggle(card, getString(R.string.full_screen), getString(R.string.hide_the_car_s_system_bars_while_carplay_is_open), AirPlayPersistence.loadHideTopBar(this) && AirPlayPersistence.loadHideBottomBar(this)) {
|
||||
AirPlayPersistence.saveHideTopBar(this, it); AirPlayPersistence.saveHideBottomBar(this, it)
|
||||
}
|
||||
}
|
||||
section(content, "Audio routing") { card ->
|
||||
val channelTitle = label("Navigation stream type", 18, TEXT, true)
|
||||
val channelHint = label("Tap a number to test. 14 = driver speaker on BYD.", 14, MUTED)
|
||||
section(content, getString(R.string.audio_routing)) { card ->
|
||||
val channelTitle = label(getString(R.string.navigation_stream_type), 18, TEXT, true)
|
||||
val channelHint = label(getString(R.string.tap_a_number_to_test_14_driver_speaker_on_byd), 14, MUTED)
|
||||
val grid = channelSelector()
|
||||
val saveButton = button("Save", true) {
|
||||
val saveButton = button(getString(R.string.save), true) {
|
||||
AirPlayPersistence.saveNavigationStreamType(this, navigationStreamType)
|
||||
toast("Saved: $navigationStreamType")
|
||||
toast(getString(R.string.audio_saved_value, navigationStreamType))
|
||||
}
|
||||
fun applyChannelEnabled(enabled: Boolean) {
|
||||
val alpha = if (enabled) 1f else 0.4f
|
||||
@@ -278,8 +278,8 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
val aaosSupported = resources.getBoolean(R.bool.config_advanced_audio_channel_mapping)
|
||||
if (aaosSupported) {
|
||||
toggle(card, "Advanced audio channel mapping",
|
||||
"Use usage / content-type routing instead of stream type",
|
||||
toggle(card, getString(R.string.advanced_audio_channel_mapping),
|
||||
getString(R.string.use_usage_content_type_routing_instead_of_stream_type),
|
||||
AirPlayPersistence.loadAdvancedAudioChannelMapping(this)) {
|
||||
AirPlayPersistence.saveAdvancedAudioChannelMapping(this, it)
|
||||
applyChannelEnabled(!it)
|
||||
@@ -291,59 +291,59 @@ class DiPlayActivity : ComponentActivity() {
|
||||
card.addView(saveButton, matchButton(12, 56))
|
||||
if (aaosSupported) applyChannelEnabled(!AirPlayPersistence.loadAdvancedAudioChannelMapping(this))
|
||||
}
|
||||
if (com.shilapi.xcertplay.hud.BydOutputSettings.available(this)) section(content, "BYD navigation", R.drawable.ic_dp_navigation) { card ->
|
||||
toggle(card, "Navigation on HUD and instrument cluster",
|
||||
"Show phone navigation arrows, distance and street names on supported BYD displays. Vehicle compatibility varies.",
|
||||
if (com.shilapi.xcertplay.hud.BydOutputSettings.available(this)) section(content, getString(R.string.byd_navigation), R.drawable.ic_dp_navigation) { card ->
|
||||
toggle(card, getString(R.string.navigation_on_hud_and_instrument_cluster),
|
||||
getString(R.string.show_phone_navigation_arrows_distance_and_street_names_on),
|
||||
com.shilapi.xcertplay.hud.BydOutputSettings.enabled(this)) { com.shilapi.xcertplay.hud.BydOutputSettings.setEnabled(this, it) }
|
||||
if (ClusterMapPresentation.findDisplay(this) != null) {
|
||||
toggle(card, "CarPlay map on instrument cluster · experimental",
|
||||
"Shows the iPhone's cluster map on the instrument cluster. Choose Small or Full screen navi in the cluster's steering-wheel menu.",
|
||||
toggle(card, getString(R.string.carplay_map_on_instrument_cluster_experimental),
|
||||
getString(R.string.shows_the_iphone_s_cluster_map_on_the_instrument_cluster_c),
|
||||
AirPlayPersistence.loadClusterMapEnabled(this)) {
|
||||
AirPlayPersistence.saveClusterMapEnabled(this, it)
|
||||
reconnectForClusterMap()
|
||||
}
|
||||
if (DiLink51ClusterLayout.supported()) {
|
||||
val automatic = DiLink51ClusterLayout.automatic(this)
|
||||
toggle(card, "Follow instrument theme and map card",
|
||||
"Show the side map only when its card is open, and switch to the full map in Map theme. Theme and card changes keep CarPlay connected.", automatic) {
|
||||
toggle(card, getString(R.string.follow_instrument_theme_and_map_card),
|
||||
getString(R.string.show_the_side_map_only_when_its_card_is_open_and_switch_to), automatic) {
|
||||
DiLink51ClusterLayout.saveAutomatic(this, it)
|
||||
render()
|
||||
reconnectForClusterMap()
|
||||
}
|
||||
val allowed = DiLink51ClusterMonitor.hasAccess(this)
|
||||
card.addView(label(if (allowed) "Usage Access: enabled"
|
||||
else "Usage Access: setup needed for automatic mode", 14, if (allowed) MUTED else WARNING))
|
||||
card.addView(button("Automatic map setup · ADB", false) { showClusterAccessSetup() }, matchButton(10, 56))
|
||||
card.addView(label(if (allowed) getString(R.string.usage_access_enabled)
|
||||
else getString(R.string.usage_access_setup_needed_for_automatic_mode), 14, if (allowed) MUTED else WARNING))
|
||||
card.addView(button(getString(R.string.automatic_map_setup_adb), false) { showClusterAccessSetup() }, matchButton(10, 56))
|
||||
if (!automatic) {
|
||||
val themes = DiLink51ClusterLayout.Theme.entries
|
||||
choice(card, "Instrument theme", themes.map { it.label }, themes.indexOf(DiLink51ClusterLayout.theme(this))) {
|
||||
choice(card, getString(R.string.instrument_theme), themes.map { it.label }, themes.indexOf(DiLink51ClusterLayout.theme(this))) {
|
||||
DiLink51ClusterLayout.saveTheme(this, themes[it])
|
||||
reconnectForClusterMap()
|
||||
}
|
||||
card.addView(label("Manual mode: match the cluster theme here. The map cannot follow card visibility without Usage Access.", 14, MUTED))
|
||||
card.addView(label(getString(R.string.manual_mode_match_the_cluster_theme_here_the_map_cannot_fo), 14, MUTED))
|
||||
}
|
||||
val contrasts = DiLink51ClusterLayout.Contrast.entries
|
||||
choice(card, "Instrument contrast", contrasts.map { it.label }, contrasts.indexOf(DiLink51ClusterLayout.contrast(this))) {
|
||||
choice(card, getString(R.string.instrument_contrast), contrasts.map { it.label }, contrasts.indexOf(DiLink51ClusterLayout.contrast(this))) {
|
||||
DiLink51ClusterLayout.saveContrast(this, contrasts[it])
|
||||
reconnectForClusterMap()
|
||||
}
|
||||
} else {
|
||||
val sizes = CarPlayClusterDisplay.scalePresets
|
||||
choice(card, "Cluster map size", listOf("Standard · sharpest", "Larger · default", "Largest"),
|
||||
choice(card, getString(R.string.cluster_map_size), listOf("Standard · sharpest", "Larger · default", "Largest"),
|
||||
sizes.indexOf(AirPlayPersistence.loadClusterMapScalePercent(this)).coerceAtLeast(0)) {
|
||||
AirPlayPersistence.saveClusterMapScalePercent(this, sizes[it])
|
||||
}
|
||||
val across = CarPlayClusterDisplay.horizontalSteps.toList()
|
||||
choice(card, "Car marker · horizontal", across.map { markerStepLabel(it, "Left", "Right") },
|
||||
choice(card, getString(R.string.car_marker_horizontal), across.map { markerStepLabel(it, "Left", "Right") },
|
||||
across.indexOf(AirPlayPersistence.loadClusterMarkerHorizontalStep(this)).coerceAtLeast(0)) {
|
||||
AirPlayPersistence.saveClusterMarkerHorizontalStep(this, across[it])
|
||||
}
|
||||
val upDown = CarPlayClusterDisplay.verticalSteps.toList()
|
||||
choice(card, "Car marker · vertical", upDown.map { markerStepLabel(it, "Up", "Down") },
|
||||
choice(card, getString(R.string.car_marker_vertical), upDown.map { markerStepLabel(it, "Up", "Down") },
|
||||
upDown.indexOf(AirPlayPersistence.loadClusterMarkerVerticalStep(this)).coerceAtLeast(0)) {
|
||||
AirPlayPersistence.saveClusterMarkerVerticalStep(this, upDown[it])
|
||||
}
|
||||
card.addView(button("Reset car marker to centre", false) {
|
||||
card.addView(button(getString(R.string.reset_car_marker_to_centre), false) {
|
||||
AirPlayPersistence.saveClusterMarkerHorizontalStep(this, 0)
|
||||
AirPlayPersistence.saveClusterMarkerVerticalStep(this, 0)
|
||||
render()
|
||||
@@ -352,25 +352,25 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
section(content, "Permissions and connection help", R.drawable.ic_dp_permissions) { card ->
|
||||
card.addView(label("Nearby devices connects your iPhone. Microphone enables Siri and calls. Older Android versions also require Location for wireless setup. USB mode may ask for a local VPN connection.", 16, MUTED))
|
||||
card.addView(button("App permissions", false) { openSystem(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName"))) }, matchButton(16, 60))
|
||||
card.addView(button("Bluetooth settings", false) { openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }, matchButton(10, 60))
|
||||
card.addView(button("Wireless connection help", false) { wirelessHelp() }, matchButton(10, 60))
|
||||
section(content, getString(R.string.permissions_and_connection_help), R.drawable.ic_dp_permissions) { card ->
|
||||
card.addView(label(getString(R.string.nearby_devices_connects_your_iphone_microphone_enables_sir), 16, MUTED))
|
||||
card.addView(button(getString(R.string.app_permissions), false) { openSystem(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName"))) }, matchButton(16, 60))
|
||||
card.addView(button(getString(R.string.bluetooth_settings), false) { openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }, matchButton(10, 60))
|
||||
card.addView(button(getString(R.string.wireless_connection_help), false) { wirelessHelp() }, matchButton(10, 60))
|
||||
}
|
||||
section(content, "About", R.drawable.ic_dp_about) { card ->
|
||||
card.addView(button("About DiPlay", false) { page = "about"; render() }, matchButton(0, 60))
|
||||
section(content, getString(R.string.about), R.drawable.ic_dp_about) { card ->
|
||||
card.addView(button(getString(R.string.about_diplay), false) { page = "about"; render() }, matchButton(0, 60))
|
||||
}
|
||||
}
|
||||
|
||||
private fun about(content: LinearLayout) {
|
||||
content.addView(label("DiPlay", 40, TEXT, true))
|
||||
content.addView(label("CarPlay, at home in your car.", 20, MUTED).apply { setPadding(0, dp(8), 0, dp(24)) })
|
||||
section(content, "Public preview · ${version()}") { card ->
|
||||
card.addView(label("An independent CarPlay receiver for Android head units. Wired and wireless connections run on the head unit, with local authentication. A standard iPhone can connect without a jailbreak, Mac, dongle or sign-in.\n\nThis preview uses an experimental accessory identity. Compatibility with every iPhone and head unit is still being tested. It is not an Apple-certified product.", 17, TEXT))
|
||||
content.addView(label(getString(R.string.diplay), 40, TEXT, true))
|
||||
content.addView(label(getString(R.string.carplay_at_home_in_your_car), 20, MUTED).apply { setPadding(0, dp(8), 0, dp(24)) })
|
||||
section(content, "${getString(R.string.about_public_preview_prefix)}${version()}") { card ->
|
||||
card.addView(label(getString(R.string.an_independent_carplay_receiver_for_android_head_units_wir), 17, TEXT))
|
||||
}
|
||||
section(content, "Made possible by open source") { card ->
|
||||
card.addView(label("Receiver based on xcertplay, licensed under GPL-3.0. DiPlay’s interface follows DiAuto’s design, licensed under AGPL-3.0.\n\nIncludes AndroidX, Bouncy Castle, JmDNS and SLF4J. Source and license notices accompany this release.\n\nCarPlay and the CarPlay icon belong to Apple Inc. DiPlay is an independent project.", 16, MUTED))
|
||||
section(content, getString(R.string.made_possible_by_open_source)) { card ->
|
||||
card.addView(label(getString(R.string.receiver_based_on_xcertplay_licensed_under_gpl_3_0_diplay), 16, MUTED))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,11 +380,11 @@ class DiPlayActivity : ComponentActivity() {
|
||||
com.shilapi.xcertplay.network.CarHotspotStatus.isEnabled(this) == false
|
||||
|
||||
private fun carHotspotOffDialog() {
|
||||
AlertDialog.Builder(this).setTitle("Car hotspot is off")
|
||||
.setMessage("DiPlay connects through the car hotspot “${AirPlayPersistence.loadManualHotspotSsid(this)}”. Turn it on in the car settings, then connect.")
|
||||
.setPositiveButton("Open car settings") { _, _ -> openCarWifiSettings() }
|
||||
.setNeutralButton("Connect") { _, _ -> connect(true) }
|
||||
.setNegativeButton("Cancel", null).show()
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.car_hotspot_is_off))
|
||||
.setMessage(getString(R.string.msg_car_hotspot_connect, AirPlayPersistence.loadManualHotspotSsid(this)))
|
||||
.setPositiveButton(getString(R.string.open_car_settings)) { _, _ -> openCarWifiSettings() }
|
||||
.setNeutralButton(getString(R.string.connect)) { _, _ -> connect(true) }
|
||||
.setNegativeButton(getString(R.string.cancel), null).show()
|
||||
}
|
||||
|
||||
// BYD maps the AOSP tether action to its own hotspot screen; other firmware falls back to Wi-Fi settings.
|
||||
@@ -413,23 +413,23 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun connectionSetup(content: LinearLayout) {
|
||||
content.addView(label("Connection setup", 34, TEXT, true))
|
||||
content.addView(label("Set up once. Your details stay saved for the next drive. Changes apply to your next connection.", 17, MUTED).apply { setPadding(0, dp(8), 0, dp(24)) })
|
||||
section(content, "1 · Choose your connection") { card -> wirelessLinkControls(card) }
|
||||
section(content, "2 · Pair your iPhone") { card ->
|
||||
card.addView(label("Keep Bluetooth and Wi-Fi on your iPhone. Pair with the car’s Bluetooth, then select your iPhone here. Allow Nearby devices when asked.", 16, MUTED))
|
||||
card.addView(button("Choose iPhone · ${DiPlayPreferences.phoneName(this)}", false) { choosePhone() }, matchButton(12, 60))
|
||||
card.addView(button("Review app permissions", false) {
|
||||
content.addView(label(getString(R.string.connection_setup), 34, TEXT, true))
|
||||
content.addView(label(getString(R.string.set_up_once_your_details_stay_saved_for_the_next_drive_cha), 17, MUTED).apply { setPadding(0, dp(8), 0, dp(24)) })
|
||||
section(content, getString(R.string.s_1_choose_your_connection)) { card -> wirelessLinkControls(card) }
|
||||
section(content, getString(R.string.s_2_pair_your_iphone)) { card ->
|
||||
card.addView(label(getString(R.string.keep_bluetooth_and_wi_fi_on_your_iphone_pair_with_the_car), 16, MUTED))
|
||||
card.addView(button("${getString(R.string.choose_iphone_prefix)}${DiPlayPreferences.phoneName(this)}", false) { choosePhone() }, matchButton(12, 60))
|
||||
card.addView(button(getString(R.string.review_app_permissions), false) {
|
||||
openSystem(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName")))
|
||||
}, matchButton(12, 60))
|
||||
}
|
||||
section(content, "3 · Connect") { card ->
|
||||
card.addView(label("Return from car settings to DiPlay, then connect. Accept the CarPlay prompt on your iPhone. A car internet plan is not required; mobile data availability depends on your phone’s network settings.", 16, MUTED))
|
||||
card.addView(button("Connect phone", true) { connect(true) }, matchButton(12, 60))
|
||||
section(content, getString(R.string.s_3_connect)) { card ->
|
||||
card.addView(label(getString(R.string.return_from_car_settings_to_diplay_then_connect_accept_the), 16, MUTED))
|
||||
card.addView(button(getString(R.string.connect_phone), true) { connect(true) }, matchButton(12, 60))
|
||||
}
|
||||
section(content, "Prefer a cable?") { card ->
|
||||
card.addView(label("Use a USB data cable and the car’s USB data port. Unlock your iPhone and allow CarPlay. No hotspot setup is needed.", 16, MUTED))
|
||||
card.addView(button("Connect with USB", false) { connect(false) }, matchButton(12, 60))
|
||||
section(content, getString(R.string.prefer_a_cable)) { card ->
|
||||
card.addView(label(getString(R.string.use_a_usb_data_cable_and_the_car_s_usb_data_port_unlock_yo), 16, MUTED))
|
||||
card.addView(button(getString(R.string.connect_with_usb), false) { connect(false) }, matchButton(12, 60))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,20 +461,20 @@ class DiPlayActivity : ComponentActivity() {
|
||||
option.addView(label(descriptions[index], 15, MUTED).apply { setPadding(0, dp(6), 0, dp(12)) })
|
||||
}
|
||||
if (mode == WirelessHotspotMode.MANUAL) {
|
||||
parent.addView(label("Hotspot setup", 22, TEXT, true))
|
||||
parent.addView(label("1. Open car hotspot settings, turn the hotspot on and select 5 GHz if available.\n2. Copy its name and password below exactly.\n3. Leave the car hotspot on when connecting. DiPlay sends the details over Bluetooth; your iPhone joins automatically.", 16, MUTED).apply { setPadding(0, dp(8), 0, dp(12)) })
|
||||
parent.addView(button("Open car hotspot settings", false) { openCarWifiSettings() }, matchButton(0, 60))
|
||||
parent.addView(button(if (pendingCarHotspotSetup) "Save hotspot details and use this mode" else "Edit saved hotspot · ${storedSsid()}", false) {
|
||||
parent.addView(label(getString(R.string.hotspot_setup), 22, TEXT, true))
|
||||
parent.addView(label(getString(R.string.s_1_open_car_hotspot_settings_turn_the_hotspot_on_and_sele), 16, MUTED).apply { setPadding(0, dp(8), 0, dp(12)) })
|
||||
parent.addView(button(getString(R.string.open_car_hotspot_settings), false) { openCarWifiSettings() }, matchButton(0, 60))
|
||||
parent.addView(button(if (pendingCarHotspotSetup) getString(R.string.save_hotspot_details_and_use_this_mode) else "${getString(R.string.edit_saved_hotspot_prefix)}${storedSsid()}", false) {
|
||||
askHotspotCredentials { ssid, password ->
|
||||
saveHotspotCredentials(ssid, password)
|
||||
pendingCarHotspotSetup = false
|
||||
applyWirelessLink(WirelessHotspotMode.MANUAL)
|
||||
}
|
||||
}, matchButton(12, 60))
|
||||
parent.addView(label(if (pendingCarHotspotSetup) "Finish setup · Save your hotspot details to use this mode." else if (carHotspotOff()) "Hotspot is off · Turn it on in car settings." else "Details saved · Check that the car hotspot is on before connecting.", 15, if (carHotspotOff()) WARNING else MUTED).apply { setPadding(0, dp(12), 0, 0) })
|
||||
parent.addView(label(if (pendingCarHotspotSetup) getString(R.string.finish_setup_save_your_hotspot_details_to_use_this_mode) else if (carHotspotOff()) "Hotspot is off · Turn it on in car settings." else "Details saved · Check that the car hotspot is on before connecting.", 15, if (carHotspotOff()) WARNING else MUTED).apply { setPadding(0, dp(12), 0, 0) })
|
||||
} else {
|
||||
parent.addView(label("Turn the car’s Wi-Fi switch on. Allow Location / Nearby devices if requested and enable Location when Android asks. If playback stutters, try the built-in car hotspot at 5 GHz.", 16, MUTED))
|
||||
parent.addView(button("Open car Wi-Fi settings", false) { openCarClientWifiSettings() }, matchButton(12, 60))
|
||||
parent.addView(label(getString(R.string.turn_the_car_s_wi_fi_switch_on_allow_location_nearby_devic), 16, MUTED))
|
||||
parent.addView(button(getString(R.string.open_car_wi_fi_settings), false) { openCarClientWifiSettings() }, matchButton(12, 60))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,10 +494,10 @@ class DiPlayActivity : ComponentActivity() {
|
||||
|
||||
private fun askHotspotCredentials(done: (String, String) -> Unit) {
|
||||
val fields = column().apply { setPadding(dp(24), dp(12), dp(24), dp(12)) }
|
||||
fields.addView(label("Copy these from the car’s hotspot settings. Use 5 GHz if available. Saving here does not change the car’s hotspot.", 16, MUTED))
|
||||
val ssid = EditText(this).apply { hint = "Hotspot name"; setText(storedSsid()); setSingleLine() }
|
||||
fields.addView(label(getString(R.string.copy_these_from_the_car_s_hotspot_settings_use_5_ghz_if_av), 16, MUTED))
|
||||
val ssid = EditText(this).apply { hint = getString(R.string.hotspot_name); setText(storedSsid()); setSingleLine() }
|
||||
val password = EditText(this).apply {
|
||||
hint = "Hotspot password"; setText(storedPassword()); setSingleLine()
|
||||
hint = getString(R.string.hotspot_password); setText(storedPassword()); setSingleLine()
|
||||
inputType = android.text.InputType.TYPE_CLASS_TEXT or android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
}
|
||||
ssid.imeOptions = android.view.inputmethod.EditorInfo.IME_ACTION_NEXT or android.view.inputmethod.EditorInfo.IME_FLAG_NO_EXTRACT_UI
|
||||
@@ -516,7 +516,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
fields.addView(ssid); fields.addView(password)
|
||||
fields.addView(CheckBox(this).apply {
|
||||
text = "Show password"
|
||||
text = getString(R.string.show_password)
|
||||
setOnCheckedChangeListener { _, checked ->
|
||||
password.transformationMethod = if (checked) null else android.text.method.PasswordTransformationMethod.getInstance()
|
||||
password.setSelection(password.text.length)
|
||||
@@ -525,10 +525,10 @@ class DiPlayActivity : ComponentActivity() {
|
||||
val error = label("", 14, WARNING)
|
||||
error.accessibilityLiveRegion = View.ACCESSIBILITY_LIVE_REGION_POLITE
|
||||
fields.addView(error)
|
||||
val dialog = AlertDialog.Builder(this).setTitle("Car hotspot details")
|
||||
val dialog = AlertDialog.Builder(this).setTitle(getString(R.string.car_hotspot_details))
|
||||
.setView(ScrollView(this).apply { addView(fields) })
|
||||
.setPositiveButton("Save details", null).setNegativeButton("Cancel") { _, _ -> hideKeyboard() }
|
||||
.setNeutralButton("Hide keyboard", null).create()
|
||||
.setPositiveButton(getString(R.string.save_details), null).setNegativeButton(getString(R.string.cancel)) { _, _ -> hideKeyboard() }
|
||||
.setNeutralButton(getString(R.string.hide_keyboard), null).create()
|
||||
dialog.setOnShowListener {
|
||||
dialog.window?.setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
dialog.getButton(android.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener { hideKeyboard() }
|
||||
@@ -553,27 +553,27 @@ class DiPlayActivity : ComponentActivity() {
|
||||
private fun showClusterAccessSetup() {
|
||||
val command = "adb shell appops set $packageName GET_USAGE_STATS allow"
|
||||
val body = column().apply { setPadding(dp(24), dp(12), dp(24), dp(12)) }
|
||||
body.addView(label("One-time setup on this car", 20, TEXT, true))
|
||||
body.addView(label("Usage Access lets DiPlay follow the instrument theme and map card. Only BYD cluster activity events are processed locally. This car does not provide a working permission settings page.", 15, MUTED))
|
||||
body.addView(label("1. Connect a computer with ADB installed to the car using your existing USB or wireless debugging connection. Approve debugging on the car if asked.\n\n2. Run this command in the computer’s terminal:", 16, TEXT))
|
||||
body.addView(label(getString(R.string.one_time_setup_on_this_car), 20, TEXT, true))
|
||||
body.addView(label(getString(R.string.usage_access_lets_diplay_follow_the_instrument_theme_and_m), 15, MUTED))
|
||||
body.addView(label(getString(R.string.s_1_connect_a_computer_with_adb_installed_to_the_car_using), 16, TEXT))
|
||||
body.addView(label(command, 16, TEXT).apply {
|
||||
typeface = android.graphics.Typeface.MONOSPACE
|
||||
setTextIsSelectable(true)
|
||||
setPadding(0, dp(16), 0, dp(16))
|
||||
})
|
||||
body.addView(button("Copy command", false) {
|
||||
body.addView(button(getString(R.string.copy_command), false) {
|
||||
getSystemService(android.content.ClipboardManager::class.java).setPrimaryClip(
|
||||
android.content.ClipData.newPlainText("DiPlay Usage Access", command))
|
||||
toast("Copied to the car clipboard. Run the command on your computer.")
|
||||
toast(getString(R.string.copied_to_the_car_clipboard_run_the_command_on_your_comput))
|
||||
}, matchButton(0, 56))
|
||||
body.addView(label("If ADB lists several devices, use adb -s <car-device-ID> shell appops set $packageName GET_USAGE_STATS allow. Find the ID with adb devices.", 14, MUTED))
|
||||
body.addView(label("3. Tap Check and enable below. This enables the cluster map and automatic theme following. An active CarPlay session reconnects once. You can then disconnect the computer.", 16, TEXT))
|
||||
body.addView(label(getString(R.string.cluster_adb_multi_device, packageName), 14, MUTED))
|
||||
body.addView(label(getString(R.string.s_3_tap_check_and_enable_below_this_enables_the_cluster_ma), 16, TEXT))
|
||||
val status = label(if (DiLink51ClusterMonitor.hasAccess(this)) "Permission enabled · ready to use" else "Permission not enabled yet", 16, TEXT)
|
||||
body.addView(status)
|
||||
val dialog = AlertDialog.Builder(this).setTitle("Automatic cluster map setup")
|
||||
val dialog = AlertDialog.Builder(this).setTitle(getString(R.string.automatic_cluster_map_setup))
|
||||
.setView(ScrollView(this).apply { addView(body) })
|
||||
.setNegativeButton("Close", null)
|
||||
.setPositiveButton("Check and enable", null).create()
|
||||
.setNegativeButton(getString(R.string.close), null)
|
||||
.setPositiveButton(getString(R.string.check_and_enable), null).create()
|
||||
dialog.setOnShowListener {
|
||||
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
|
||||
if (DiLink51ClusterMonitor.hasAccess(this)) {
|
||||
@@ -581,10 +581,10 @@ class DiPlayActivity : ComponentActivity() {
|
||||
DiLink51ClusterLayout.saveAutomatic(this, true)
|
||||
dialog.dismiss()
|
||||
render()
|
||||
toast("Automatic map enabled. Open the cluster map card or select Map theme.")
|
||||
toast(getString(R.string.automatic_map_enabled_open_the_cluster_map_card_or_select))
|
||||
reconnectForClusterMap()
|
||||
} else {
|
||||
status.text = "Still waiting for Usage Access. Check that the command ran successfully for this car, then try again."
|
||||
status.text = getString(R.string.still_waiting_for_usage_access_check_that_the_command_ran)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -592,7 +592,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
// The cluster screen is described at connection time, so a running session reconnects over
|
||||
// its current link. The position choices need no call: "Apply and reconnect" already does it.
|
||||
// its current link. The position choices need no call: getString(R.string.apply_and_reconnect) already does it.
|
||||
private fun reconnectForClusterMap() {
|
||||
if (CarPlayBackgroundSession.hasSession()) connect(AirPlayPersistence.loadWirelessEnabled(this))
|
||||
}
|
||||
@@ -600,7 +600,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
private fun applyWirelessLink(mode: WirelessHotspotMode) {
|
||||
AirPlayPersistence.saveWirelessHotspotMode(this, mode)
|
||||
render()
|
||||
toast("Saved for your next connection")
|
||||
toast(getString(R.string.saved_for_your_next_connection))
|
||||
}
|
||||
|
||||
private fun textInput(title: String, current: String, secret: Boolean, save: (String) -> Unit) {
|
||||
@@ -614,30 +614,30 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
}
|
||||
AlertDialog.Builder(this).setTitle(title).setView(input)
|
||||
.setPositiveButton("Save") { _, _ -> save(input.text.toString().let { if (secret) it else it.trim() }) }
|
||||
.setNegativeButton("Cancel", null).show()
|
||||
.setPositiveButton(getString(R.string.save)) { _, _ -> save(input.text.toString().let { if (secret) it else it.trim() }) }
|
||||
.setNegativeButton(getString(R.string.cancel), null).show()
|
||||
}
|
||||
|
||||
private fun carPlaySizeControl(parent: LinearLayout) {
|
||||
val sizes = com.shilapi.xcertplay.airplay.CarPlaySize.entries
|
||||
val current = com.shilapi.xcertplay.airplay.CarPlaySize.fromWidthMillimeters(AirPlayPersistence.loadWidthPhysicalMm(this))
|
||||
choice(parent, "CarPlay size", sizes.map { it.label }, sizes.indexOf(current)) {
|
||||
choice(parent, getString(R.string.carplay_size), sizes.map { it.label }, sizes.indexOf(current)) {
|
||||
AirPlayPersistence.saveWidthPhysicalMm(this, sizes[it].widthMillimeters)
|
||||
}
|
||||
parent.addView(label("Changes the size of CarPlay icons and text. Applying a size reconnects CarPlay.", 14, MUTED).apply {
|
||||
parent.addView(label(getString(R.string.changes_the_size_of_carplay_icons_and_text_applying_a_size), 14, MUTED).apply {
|
||||
setPadding(0, 0, 0, dp(18))
|
||||
})
|
||||
}
|
||||
|
||||
private fun connect(wireless: Boolean) {
|
||||
if (wireless && pendingCarHotspotSetup) { toast("Save your hotspot details in Connection setup first"); page = "connection"; render(); return }
|
||||
if (wireless && pendingCarHotspotSetup) { toast(getString(R.string.save_your_hotspot_details_in_connection_setup_first)); page = "connection"; render(); return }
|
||||
if (setupError != null) { toast(setupError!!); return }
|
||||
if (wireless && AirPlayPersistence.loadWirelessHotspotMode(this) == WirelessHotspotMode.MANUAL &&
|
||||
hotspotError(storedSsid(), storedPassword()) != null) {
|
||||
pendingCarHotspotSetup = true
|
||||
page = "connection"
|
||||
render()
|
||||
toast("Save the name and password from the car’s hotspot settings first")
|
||||
toast(getString(R.string.save_the_name_and_password_from_the_car_s_hotspot_settings))
|
||||
return
|
||||
}
|
||||
if (wireless && carHotspotOff()) { carHotspotOffDialog(); return }
|
||||
@@ -667,21 +667,21 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
val adapter = getSystemService(BluetoothManager::class.java)?.adapter
|
||||
if (adapter == null || !adapter.isEnabled) {
|
||||
AlertDialog.Builder(this).setTitle("Turn on Bluetooth")
|
||||
.setMessage("Enable the car’s Bluetooth and pair your iPhone first.")
|
||||
.setPositiveButton("Open Bluetooth") { _, _ -> openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }
|
||||
.setNegativeButton("Later", null).show(); return
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.turn_on_bluetooth))
|
||||
.setMessage(getString(R.string.enable_the_car_s_bluetooth_and_pair_your_iphone_first))
|
||||
.setPositiveButton(getString(R.string.open_bluetooth)) { _, _ -> openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }
|
||||
.setNegativeButton(getString(R.string.later), null).show(); return
|
||||
}
|
||||
val devices = runCatching { adapter.bondedDevices.sortedBy { it.name ?: "" } }.getOrDefault(emptyList())
|
||||
if (devices.isEmpty()) {
|
||||
AlertDialog.Builder(this).setTitle("Pair your iPhone")
|
||||
.setMessage("On your iPhone, open Settings → Bluetooth and pair with the car. Then return to DiPlay and choose Connect phone.")
|
||||
.setPositiveButton("Open Bluetooth") { _, _ -> openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }
|
||||
.setNegativeButton("Got it", null).show(); return
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.pair_your_iphone))
|
||||
.setMessage(getString(R.string.on_your_iphone_open_settings_bluetooth_and_pair_with_the_c))
|
||||
.setPositiveButton(getString(R.string.open_bluetooth)) { _, _ -> openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }
|
||||
.setNegativeButton(getString(R.string.got_it), null).show(); return
|
||||
}
|
||||
AlertDialog.Builder(this).setTitle("Choose your iPhone")
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.choose_your_iphone))
|
||||
.setItems(devices.map { device ->
|
||||
val name = device.name ?: "Paired device"
|
||||
val name = device.name ?: getString(R.string.paired_device)
|
||||
if (devices.count { it.name == device.name } > 1) "$name · ${device.address.takeLast(5)}" else name
|
||||
}.toTypedArray()) { _, index ->
|
||||
val device = devices[index]
|
||||
@@ -689,15 +689,15 @@ class DiPlayActivity : ComponentActivity() {
|
||||
val start = pendingWireless; pendingWireless = false
|
||||
render()
|
||||
if (start) connect(true)
|
||||
}.setNeutralButton("Pair another") { _, _ -> openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }
|
||||
.setNegativeButton("Cancel") { _, _ -> pendingWireless = false }.show()
|
||||
}.setNeutralButton(getString(R.string.pair_another)) { _, _ -> openSystem(Intent(Settings.ACTION_BLUETOOTH_SETTINGS)) }
|
||||
.setNegativeButton(getString(R.string.cancel)) { _, _ -> pendingWireless = false }.show()
|
||||
}
|
||||
|
||||
private fun wirelessHelp() {
|
||||
AlertDialog.Builder(this).setTitle("Wireless connection help")
|
||||
.setMessage("Pair your iPhone with the car’s Bluetooth, keep Wi-Fi on, and allow CarPlay on the iPhone. Close any other phone-projection app.\n\nIf a previous projection app left its connection running, reset CarPlay Wi-Fi below and connect again. Your car’s normal internet Wi-Fi stays on.")
|
||||
.setPositiveButton("Got it", null)
|
||||
.setNeutralButton("Reset CarPlay Wi-Fi") { _, _ ->
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.wireless_connection_help))
|
||||
.setMessage(getString(R.string.pair_your_iphone_with_the_car_s_bluetooth_keep_wi_fi_on_an))
|
||||
.setPositiveButton(getString(R.string.got_it), null)
|
||||
.setNeutralButton(getString(R.string.reset_carplay_wi_fi)) { _, _ ->
|
||||
confirmWirelessReset()
|
||||
}.show()
|
||||
}
|
||||
@@ -709,16 +709,16 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
private fun confirmWirelessReset() {
|
||||
AlertDialog.Builder(this).setTitle("Reset CarPlay Wi-Fi?")
|
||||
.setMessage("This ends the existing Wi-Fi Direct connection, including one left behind after reinstalling. Close other projection apps first. Your car’s internet Wi-Fi stays on.")
|
||||
.setPositiveButton("Reset and connect") { _, _ ->
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.reset_carplay_wi_fi_2))
|
||||
.setMessage(getString(R.string.this_ends_the_existing_wi_fi_direct_connection_including_o))
|
||||
.setPositiveButton(getString(R.string.reset_and_connect)) { _, _ ->
|
||||
CarPlayBackgroundSession.stop { runOnUiThread { resetWirelessGroup() } }
|
||||
}.setNegativeButton("Cancel", null).show()
|
||||
}.setNegativeButton(getString(R.string.cancel), null).show()
|
||||
}
|
||||
|
||||
private fun resetWirelessGroup() {
|
||||
val manager = getSystemService(android.net.wifi.p2p.WifiP2pManager::class.java)
|
||||
if (manager == null) { toast("This head unit does not support Wi-Fi Direct."); return }
|
||||
if (manager == null) { toast(getString(R.string.this_head_unit_does_not_support_wi_fi_direct)); return }
|
||||
val channel = manager.initialize(this, mainLooper, null)
|
||||
try {
|
||||
manager.requestGroupInfo(channel) { group ->
|
||||
@@ -731,7 +731,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
when {
|
||||
remaining == null -> { channel.close(); if (!isFinishing && !isDestroyed) connect(true) }
|
||||
android.os.SystemClock.elapsedRealtime() >= deadline -> {
|
||||
channel.close(); toast("Wi-Fi Direct is still busy. Close the other projection app and try again.")
|
||||
channel.close(); toast(getString(R.string.wi_fi_direct_is_still_busy_close_the_other_projection_app))
|
||||
}
|
||||
else -> handler.postDelayed({ waitUntilRemoved() }, 200)
|
||||
}
|
||||
@@ -739,25 +739,25 @@ class DiPlayActivity : ComponentActivity() {
|
||||
}
|
||||
waitUntilRemoved()
|
||||
}
|
||||
override fun onFailure(reason: Int) { channel.close(); toast("Could not reset Wi-Fi Direct. Close the other projection app and try again.") }
|
||||
override fun onFailure(reason: Int) { channel.close(); toast(getString(R.string.could_not_reset_wi_fi_direct_close_the_other_projection_ap)) }
|
||||
})
|
||||
}
|
||||
} catch (_: SecurityException) {
|
||||
channel.close(); permissionHelp("Wireless permissions", "Allow Nearby devices and, on older Android versions, Location before resetting CarPlay Wi-Fi.")
|
||||
channel.close(); permissionHelp(getString(R.string.wireless_permissions), getString(R.string.allow_nearby_devices_and_on_older_android_versions_locatio))
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshStatus() {
|
||||
val running = CarPlayBackgroundSession.hasSession()
|
||||
status?.text = when {
|
||||
setupError != null -> "Setup needs attention"
|
||||
CarPlayBackgroundSession.active -> "CarPlay connected"
|
||||
running -> "Connecting to your iPhone…"
|
||||
DiPlayPreferences.phoneAddress(this) != null -> "Ready for ${DiPlayPreferences.phoneName(this)}"
|
||||
else -> "Ready when you are"
|
||||
setupError != null -> getString(R.string.setup_needs_attention)
|
||||
CarPlayBackgroundSession.active -> getString(R.string.carplay_connected)
|
||||
running -> getString(R.string.connecting_to_your_iphone)
|
||||
DiPlayPreferences.phoneAddress(this) != null -> "${getString(R.string.status_ready_for_prefix)}${DiPlayPreferences.phoneName(this)}"
|
||||
else -> getString(R.string.ready_when_you_are)
|
||||
}
|
||||
if (lastRunning != running) {
|
||||
connectButton?.text = if (running) "Open CarPlay" else "Connect phone"
|
||||
connectButton?.text = if (running) getString(R.string.open_carplay) else getString(R.string.connect_phone)
|
||||
disconnectButton?.visibility = if (running) View.VISIBLE else View.GONE
|
||||
disconnectButton?.isEnabled = true
|
||||
lastRunning = running
|
||||
@@ -771,15 +771,15 @@ class DiPlayActivity : ComponentActivity() {
|
||||
// the result callback and the background writer's exception handler ever run.
|
||||
runCatching { export.launch(reportFileName()) }.onFailure {
|
||||
toast(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
|
||||
"This head unit could not open a save location. Please try saving to Downloads again."
|
||||
else "This head unit has no available file picker to save the report.")
|
||||
getString(R.string.this_head_unit_could_not_open_a_save_location_please_try_s)
|
||||
else getString(R.string.this_head_unit_has_no_available_file_picker_to_save_the_re))
|
||||
}
|
||||
}
|
||||
|
||||
private fun exportDiagnostics(uri: Uri? = null) {
|
||||
if (exportInProgress) return
|
||||
exportInProgress = true
|
||||
exportButton?.apply { isEnabled = false; text = "Saving report…" }
|
||||
exportButton?.apply { isEnabled = false; text = getString(R.string.saving_report) }
|
||||
val appContext = applicationContext
|
||||
val fileName = reportFileName()
|
||||
Thread({
|
||||
@@ -816,36 +816,36 @@ class DiPlayActivity : ComponentActivity() {
|
||||
runOnUiThread {
|
||||
exportInProgress = false
|
||||
if (isFinishing || isDestroyed) return@runOnUiThread
|
||||
exportButton?.apply { isEnabled = true; text = "Save diagnostic report" }
|
||||
exportButton?.apply { isEnabled = true; text = getString(R.string.save_diagnostic_report) }
|
||||
if (result.isSuccess) {
|
||||
val savedUri = result.getOrThrow()
|
||||
AlertDialog.Builder(this).setTitle("Diagnostic report saved")
|
||||
.setMessage(if (uri == null) "Downloads/DiPlay/$fileName" else "Your report was saved to the selected location.")
|
||||
.setPositiveButton("Done", null)
|
||||
.setNeutralButton("Share") { _, _ ->
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.diagnostic_report_saved))
|
||||
.setMessage(if (uri == null) "Downloads/DiPlay/$fileName" else getString(R.string.your_report_was_saved_to_the_selected_location))
|
||||
.setPositiveButton(getString(R.string.done), null)
|
||||
.setNeutralButton(getString(R.string.share)) { _, _ ->
|
||||
runCatching {
|
||||
startActivity(Intent.createChooser(Intent(Intent.ACTION_SEND).apply {
|
||||
type = "text/plain"; putExtra(Intent.EXTRA_STREAM, savedUri)
|
||||
clipData = android.content.ClipData.newRawUri("Diagnostic report", savedUri)
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}, "Share diagnostic report"))
|
||||
}.onFailure { toast("Report saved. Open it from your file manager to share it.") }
|
||||
}.onFailure { toast(getString(R.string.report_saved_open_it_from_your_file_manager_to_share_it)) }
|
||||
}.show()
|
||||
} else {
|
||||
AlertDialog.Builder(this).setTitle("Could not save the report")
|
||||
.setMessage("Check that storage is available, or choose another save location.")
|
||||
.setPositiveButton("Choose location") { _, _ -> chooseReportDestination() }
|
||||
.setNegativeButton("Close", null).show()
|
||||
AlertDialog.Builder(this).setTitle(getString(R.string.could_not_save_the_report))
|
||||
.setMessage(getString(R.string.check_that_storage_is_available_or_choose_another_save_loc))
|
||||
.setPositiveButton(getString(R.string.choose_location)) { _, _ -> chooseReportDestination() }
|
||||
.setNegativeButton(getString(R.string.close), null).show()
|
||||
}
|
||||
}
|
||||
}, "diplay-export").start()
|
||||
}
|
||||
private fun permissionHelp(title: String, body: String) {
|
||||
AlertDialog.Builder(this).setTitle(title).setMessage(body).setPositiveButton("App settings") { _, _ ->
|
||||
AlertDialog.Builder(this).setTitle(title).setMessage(body).setPositiveButton(getString(R.string.app_settings)) { _, _ ->
|
||||
openSystem(Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:$packageName")))
|
||||
}.setNegativeButton("Later", null).show()
|
||||
}.setNegativeButton(getString(R.string.later), null).show()
|
||||
}
|
||||
private fun openSystem(intent: Intent) { runCatching { startActivity(intent) }.onFailure { toast("Open this setting from your car’s Settings app.") } }
|
||||
private fun openSystem(intent: Intent) { runCatching { startActivity(intent) }.onFailure { toast(getString(R.string.open_this_setting_from_your_car_s_settings_app)) } }
|
||||
private fun toast(message: String) { Toast.makeText(this, message, Toast.LENGTH_LONG).show() }
|
||||
|
||||
private fun playTestTone(streamType: Int) {
|
||||
@@ -865,7 +865,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
if (track.state != AudioTrack.STATE_INITIALIZED) {
|
||||
Log.w("DiPlay", "playTestTone streamType=$streamType state=${track.state}")
|
||||
track.release()
|
||||
toast("Stream type $streamType is unavailable here (state=${track.state})")
|
||||
toast(getString(R.string.audio_stream_unavailable, streamType, track.state))
|
||||
return
|
||||
}
|
||||
track.write(pcm, 0, pcm.size)
|
||||
@@ -982,7 +982,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
var pendingSelection = selection
|
||||
AlertDialog.Builder(this).setTitle(title)
|
||||
.setSingleChoiceItems(options.toTypedArray(), selection) { _, index -> pendingSelection = index }
|
||||
.setPositiveButton(if (CarPlayBackgroundSession.hasSession()) "Apply and reconnect" else "Save") { _, _ ->
|
||||
.setPositiveButton(if (CarPlayBackgroundSession.hasSession()) getString(R.string.apply_and_reconnect) else getString(R.string.save)) { _, _ ->
|
||||
if (pendingSelection != selection) {
|
||||
selection = pendingSelection
|
||||
save(selection)
|
||||
@@ -991,7 +991,7 @@ class DiPlayActivity : ComponentActivity() {
|
||||
connect(AirPlayPersistence.loadWirelessEnabled(this))
|
||||
}
|
||||
}
|
||||
}.setNegativeButton("Cancel", null).show()
|
||||
}.setNegativeButton(getString(R.string.cancel), null).show()
|
||||
}
|
||||
parent.addView(button, matchButton(0, 60)); parent.addView(space(12))
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.widget.Button
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import com.shilapi.xcertplay.host.R
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.util.concurrent.Executors
|
||||
import kotlin.math.ceil
|
||||
@@ -51,7 +52,7 @@ class ImageCropActivity : Activity() {
|
||||
textSize = 16f
|
||||
gravity = Gravity.CENTER
|
||||
setPadding(dp(12), dp(8), dp(12), dp(8))
|
||||
text = "Loading image"
|
||||
text = getString(R.string.loading_image)
|
||||
}
|
||||
|
||||
val controls = LinearLayout(this).apply {
|
||||
@@ -61,7 +62,7 @@ class ImageCropActivity : Activity() {
|
||||
}
|
||||
controls.addView(
|
||||
Button(this).apply {
|
||||
text = "Cancel"
|
||||
text = getString(R.string.cancel)
|
||||
isAllCaps = false
|
||||
setOnClickListener {
|
||||
setResult(RESULT_CANCELED)
|
||||
@@ -72,7 +73,7 @@ class ImageCropActivity : Activity() {
|
||||
)
|
||||
controls.addView(
|
||||
Button(this).apply {
|
||||
text = "Save 1:1"
|
||||
text = getString(R.string.save_1_1)
|
||||
isAllCaps = false
|
||||
setOnClickListener { saveCrop() }
|
||||
},
|
||||
@@ -121,10 +122,10 @@ class ImageCropActivity : Activity() {
|
||||
return@runOnUiThread
|
||||
}
|
||||
if (bitmap == null) {
|
||||
statusView.text = "Could not decode image"
|
||||
statusView.text = getString(R.string.could_not_decode_image)
|
||||
} else {
|
||||
cropView.setBitmap(bitmap)
|
||||
statusView.text = "Drag to move, pinch to zoom"
|
||||
statusView.text = getString(R.string.drag_to_move_pinch_to_zoom)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,13 +139,13 @@ class ImageCropActivity : Activity() {
|
||||
|
||||
private fun saveCrop() {
|
||||
val cropped = cropView.cropToSquare() ?: run {
|
||||
statusView.text = "Image is not ready"
|
||||
statusView.text = getString(R.string.image_is_not_ready)
|
||||
return
|
||||
}
|
||||
val encoded = ByteArrayOutputStream().use { output ->
|
||||
if (!cropped.compress(Bitmap.CompressFormat.PNG, 100, output)) {
|
||||
cropped.recycle()
|
||||
statusView.text = "Could not encode image"
|
||||
statusView.text = getString(R.string.could_not_encode_image)
|
||||
return
|
||||
}
|
||||
cropped.recycle()
|
||||
@@ -158,7 +159,7 @@ class ImageCropActivity : Activity() {
|
||||
)
|
||||
finish()
|
||||
} catch (_: Exception) {
|
||||
statusView.text = "Could not save image"
|
||||
statusView.text = getString(R.string.could_not_save_image)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,340 @@
|
||||
<resources>
|
||||
<string name="msg_car_hotspot_off">车机热点“%1$s”未开启。请在车机设置中开启后再连接。</string>
|
||||
<string name="home_public_preview">公开预览 ·\u0020\u0020</string>
|
||||
<string name="choose_iphone_prefix">选择 iPhone ·\u0020</string>
|
||||
<string name="audio_saved_value">已保存:%1$d</string>
|
||||
<string name="about_public_preview_prefix">公开预览 ·\u0020</string>
|
||||
<string name="msg_car_hotspot_connect">DiPlay 通过车机热点“%1$s”连接。请在车机设置中开启热点后连接。</string>
|
||||
<string name="edit_saved_hotspot_prefix">编辑已保存的热点 ·\u0020</string>
|
||||
<string name="cluster_adb_multi_device">如果 ADB 列出多个设备,请使用 adb -s <car-device-ID> shell appops set %1$s GET_USAGE_STATS allow。用 adb devices 查询 ID。</string>
|
||||
<string name="status_ready_for_prefix">已准备连接:</string>
|
||||
<string name="audio_stream_unavailable">流类型 %1$d 在此不可用(状态=%2$s)</string>
|
||||
<string name="resolution_handshake_prefix">握手分辨率:</string>
|
||||
<string name="safe_area_full_screen_at">安全区域:全屏,</string>
|
||||
<string name="safe_area_prefix">安全区域:</string>
|
||||
<string name="settings_android9_compat">以下设置在 Android 9(API 28)上不可用且已隐藏:\n• Wi-Fi P2P(5 GHz)— 将改用 LocalOnlyHotspot。\n• HEVC 软解码器 — 将改用硬件解码。</string>
|
||||
<string name="settings_mfi_address_hint">地址必须以 http:// 或 https:// 开头。令牌为可选项,将作为 Authorization bearer token 发送。</string>
|
||||
<string name="a_familiar_drive">熟悉的驾乘体验。</string>
|
||||
<string name="a_previous_wi_fi_direct_connection_is_still_running_reset">之前的 Wi-Fi Direct 连接仍在运行。请重置后再连接。</string>
|
||||
<string name="about">关于</string>
|
||||
<string name="about_diplay">关于 DiPlay</string>
|
||||
<string name="active">已启用</string>
|
||||
<string name="advanced_audio_channel_mapping">高级音频通道映射</string>
|
||||
<string name="airplay_icon">AirPlay 图标</string>
|
||||
<string name="allow_carplay_ui_outside_the_safe_area">允许 CarPlay 界面超出安全区域</string>
|
||||
<string name="allow_nearby_devices_and_on_older_android_versions_locatio">重置 CarPlay Wi-Fi 前,请授予“附近的设备”权限;较旧的 Android 版本还需要位置权限。</string>
|
||||
<string name="allow_nearby_devices_for_diplay_in_the_head_unit_s_app_per">请在车机应用权限中允许 DiPlay 访问附近的设备。</string>
|
||||
<string name="allow_nearby_devices_so_diplay_can_connect_to_your_paired">请允许 DiPlay 访问附近的设备,以连接已配对的 iPhone。</string>
|
||||
<string name="allow_precise_location_for_diplay_in_the_head_unit_s_app_p">请在车机应用权限中允许 DiPlay 使用精确位置信息。</string>
|
||||
<string name="allow_the_connection_permission_to_continue">请授予连接权限以继续</string>
|
||||
<string name="an_independent_carplay_receiver_for_android_head_units_wir">面向 Android 车机的独立 CarPlay 接收器。有线和无线连接均在车机上运行,并使用本地认证。普通 iPhone 无需越狱、Mac、转接器或登录即可连接。\n\n此预览版使用实验性配件身份,仍在测试与不同 iPhone 和车机的兼容性。本产品未经 Apple 认证。</string>
|
||||
<string name="android_9_compatibility">Android 9 兼容性</string>
|
||||
<string name="app_name">DiPlay</string>
|
||||
<string name="app_permissions">应用权限</string>
|
||||
<string name="app_settings">应用设置</string>
|
||||
<string name="apply_and_reconnect">应用并重新连接</string>
|
||||
<string name="apply_reconnects_carplay_for_size_resolution_music_buffer">应用尺寸、分辨率、音乐缓冲和帧率设置时会重新连接 CarPlay。其他改动将在下次连接时生效。</string>
|
||||
<string name="audio">音频</string>
|
||||
<string name="audio_routing">音频路由</string>
|
||||
<string name="auto">自动</string>
|
||||
<string name="auto_start_on_boot">开机后自动启动</string>
|
||||
<string name="automatic_cluster_map_setup">自动仪表盘地图设置</string>
|
||||
<string name="automatic_connection">自动连接</string>
|
||||
<string name="automatic_map_enabled_open_the_cluster_map_card_or_select">自动地图已启用。打开仪表盘地图卡片或选择“地图主题”。</string>
|
||||
<string name="automatic_map_setup_adb">自动地图设置 · ADB</string>
|
||||
<string name="availability_depends_on_your_head_unit_s_startup_settings">是否可用取决于车机的启动设置。</string>
|
||||
<string name="back">返回</string>
|
||||
<string name="back_to_diplay">返回 DiPlay</string>
|
||||
<string name="band">频段</string>
|
||||
<string name="bluetooth_settings">蓝牙设置</string>
|
||||
<string name="byd_navigation">比亚迪导航</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="car_home">车机主页</string>
|
||||
<string name="car_hotspot_details">车机热点详情</string>
|
||||
<string name="car_hotspot_is_off">车机热点未开启</string>
|
||||
<string name="car_marker_horizontal">车辆标记 · 水平</string>
|
||||
<string name="car_marker_vertical">车辆标记 · 垂直</string>
|
||||
<string name="carplay">CarPlay</string>
|
||||
<string name="carplay_at_home_in_your_car">让 CarPlay 融入车机。</string>
|
||||
<string name="carplay_connected">CarPlay 已连接</string>
|
||||
<string name="carplay_control_running">CarPlay 控制通道运行中</string>
|
||||
<string name="carplay_control_window_ended">CarPlay 控制会话已结束</string>
|
||||
<string name="carplay_icon">CarPlay 图标</string>
|
||||
<string name="carplay_map_on_instrument_cluster_experimental">仪表盘显示 CarPlay 地图 · 实验性</string>
|
||||
<string name="carplay_service_already_running">CarPlay 服务已在运行</string>
|
||||
<string name="carplay_session_already_running">CarPlay 会话已在运行</string>
|
||||
<string name="carplay_session_ended_reconnecting">CarPlay 会话已结束;正在重新连接</string>
|
||||
<string name="carplay_settings">CarPlay 设置</string>
|
||||
<string name="carplay_size">CarPlay 尺寸</string>
|
||||
<string name="changes_the_size_of_carplay_icons_and_text_applying_a_size">更改 CarPlay 图标和文字的大小。应用尺寸后会重新连接 CarPlay。</string>
|
||||
<string name="channel_0_auto">信道(0 = 自动)</string>
|
||||
<string name="channel_is_not_valid_for_the_selected_band">所选频段不支持此信道</string>
|
||||
<string name="channel_must_be_0_or_1_196">信道必须为 0 或 1–196</string>
|
||||
<string name="check_and_enable">检查并启用</string>
|
||||
<string name="check_that_storage_is_available_or_choose_another_save_loc">请检查存储空间,或选择其他保存位置。</string>
|
||||
<string name="choose_how_to_connect_follow_the_setup_steps_and_save_your">选择连接方式,按步骤操作并保存车机热点信息。</string>
|
||||
<string name="choose_image">选择图片</string>
|
||||
<string name="choose_iphone">选择 iPhone</string>
|
||||
<string name="choose_location">选择位置</string>
|
||||
<string name="choose_save_location">选择保存位置</string>
|
||||
<string name="choose_where_to_save_your_report">选择报告的保存位置。</string>
|
||||
<string name="choose_your_iphone">选择 iPhone</string>
|
||||
<string name="close">关闭</string>
|
||||
<string name="cluster_map_size">仪表盘地图尺寸</string>
|
||||
<string name="common_cancel">取消</string>
|
||||
<string name="connect">连接</string>
|
||||
<string name="connect_phone">连接手机</string>
|
||||
<string name="connect_when_diplay_opens">打开 DiPlay 时连接</string>
|
||||
<string name="connect_with_usb">通过 USB 连接</string>
|
||||
<string name="connect_your_iphone_with_a_usb_cable">请使用 USB 数据线连接 iPhone</string>
|
||||
<string name="connecting_bluetooth">正在连接蓝牙</string>
|
||||
<string name="connecting_iap2_control">正在连接 iAP2 控制通道</string>
|
||||
<string name="connecting_to_your_iphone">正在连接 iPhone…</string>
|
||||
<string name="connection">连接</string>
|
||||
<string name="connection_interrupted_retrying">连接中断,正在重试…</string>
|
||||
<string name="connection_setup">连接设置</string>
|
||||
<string name="copied_to_the_car_clipboard_run_the_command_on_your_comput">已复制到车机剪贴板。在电脑上运行该命令。</string>
|
||||
<string name="copy_command">复制命令</string>
|
||||
<string name="copy_these_from_the_car_s_hotspot_settings_use_5_ghz_if_av">从车机热点设置中复制以下内容。如有 5 GHz 请选择。在此保存不会更改车机的热点。</string>
|
||||
<string name="could_not_decode_image">无法读取图片</string>
|
||||
<string name="could_not_encode_image">无法编码图片</string>
|
||||
<string name="could_not_reset_wi_fi_direct_close_the_other_projection_ap">无法重置 Wi-Fi Direct。请关闭其他投屏应用后重试。</string>
|
||||
<string name="could_not_save_image">无法保存图片</string>
|
||||
<string name="could_not_save_the_report">无法保存报告</string>
|
||||
<string name="could_not_start_carplay_return_to_diplay_and_check_app_per">无法启动 CarPlay。请返回 DiPlay 检查应用权限。</string>
|
||||
<string name="custom_1_1_icon">自定义 1:1 图标</string>
|
||||
<string name="debug_logs">调试日志</string>
|
||||
<string name="default_icon">默认图标</string>
|
||||
<string name="default_placeholder_icon">默认占位图标</string>
|
||||
<string name="diagnostic_report_saved">诊断报告已保存</string>
|
||||
<string name="diagnostics">诊断</string>
|
||||
<string name="diplay">DiPlay</string>
|
||||
<string name="discard_changes_and_exit_settings">放弃更改并退出设置</string>
|
||||
<string name="disconnect">断开连接</string>
|
||||
<string name="discovering_iphone">正在查找 iPhone</string>
|
||||
<string name="display_and_performance">显示与性能</string>
|
||||
<string name="display_video">显示与视频</string>
|
||||
<string name="done">完成</string>
|
||||
<string name="drag_to_move_pinch_to_zoom">拖动以移动,双指缩放</string>
|
||||
<string name="draw_outside_safe_area">允许绘制到安全区域外</string>
|
||||
<string name="driving_side">驾驶方向</string>
|
||||
<string name="efficient_video">高效视频</string>
|
||||
<string name="enable_the_car_s_bluetooth_and_pair_your_iphone_first">请先打开车机蓝牙并配对 iPhone。</string>
|
||||
<string name="error">错误</string>
|
||||
<string name="exit_application">退出应用</string>
|
||||
<string name="finish_setup_save_your_hotspot_details_to_use_this_mode">完成设置 · 保存热点信息以使用此模式。</string>
|
||||
<string name="follow_instrument_theme_and_map_card">跟随仪表盘主题和地图卡片</string>
|
||||
<string name="frame_rate">帧率</string>
|
||||
<string name="full_screen">全屏显示</string>
|
||||
<string name="fullscreen">全屏</string>
|
||||
<string name="getting_carplay_ready">正在准备 CarPlay…</string>
|
||||
<string name="got_it">知道了</string>
|
||||
<string name="handshake_resolution_waiting_for_display">握手分辨率:正在等待显示屏</string>
|
||||
<string name="hevc_h_265_video_transport">HEVC H.265 视频传输</string>
|
||||
<string name="hevc_software_decoder">HEVC 软件解码器</string>
|
||||
<string name="hide_bottom_bar">隐藏底部导航栏</string>
|
||||
<string name="hide_keyboard">隐藏键盘</string>
|
||||
<string name="hide_the_car_s_system_bars_while_carplay_is_open">打开 CarPlay 时隐藏车机系统栏。</string>
|
||||
<string name="hide_the_navigation_bar">隐藏导航栏</string>
|
||||
<string name="hide_the_status_bar">隐藏状态栏</string>
|
||||
<string name="hide_top_bar">隐藏顶部状态栏</string>
|
||||
<string name="hotspot_name">热点名称</string>
|
||||
<string name="hotspot_password">热点密码</string>
|
||||
<string name="hotspot_password_contains_u_0000">热点密码包含 U+0000</string>
|
||||
<string name="hotspot_setup">热点设置</string>
|
||||
<string name="hotspot_ssid">热点 SSID</string>
|
||||
<string name="hotspot_ssid_contains_u_0000">热点 SSID 包含 U+0000</string>
|
||||
<string name="hotspot_ssid_is_required">必须填写热点 SSID</string>
|
||||
<string name="hotspot_ssid_must_be_at_most_32_utf_8_bytes">热点 SSID 最多为 32 个 UTF-8 字节</string>
|
||||
<string name="hotspot_status">热点状态</string>
|
||||
<string name="i2c">I2C</string>
|
||||
<string name="i2c_device">I2C 设备</string>
|
||||
<string name="i2c_device_path_contains_u_0000">I2C 设备路径包含 U+0000</string>
|
||||
<string name="i2c_device_path_is_required">必须填写 I2C 设备路径</string>
|
||||
<string name="identity_appearance">身份与外观</string>
|
||||
<string name="image_is_not_ready">图片尚未准备好</string>
|
||||
<string name="in_carplay_swipe_down_with_three_fingers_to_open_diplay_se">在 CarPlay 界面用三指向下滑动,可打开 DiPlay 设置。</string>
|
||||
<string name="instrument_contrast">仪表盘对比度</string>
|
||||
<string name="instrument_theme">仪表盘主题</string>
|
||||
<string name="keep_bluetooth_and_wi_fi_on_your_iphone_pair_with_the_car">保持 iPhone 的蓝牙和 Wi-Fi 开启。先与车机蓝牙配对,然后在此选择你的 iPhone。出现提示时允许“附近的设备”。</string>
|
||||
<string name="keep_your_iphone_nearby_with_bluetooth_and_wi_fi_on_allow">请将 iPhone 放在附近并开启蓝牙和 Wi-Fi。\niPhone 出现提示时允许使用 CarPlay。</string>
|
||||
<string name="language_app_language">应用语言</string>
|
||||
<string name="language_apply">应用</string>
|
||||
<string name="language_hint">选择 DiPlay 的语言。“跟随系统”将使用设备语言。</string>
|
||||
<string name="language_section_title">语言</string>
|
||||
<string name="language_system_default">跟随系统</string>
|
||||
<string name="later">稍后</string>
|
||||
<string name="left_hand_drive">左舵</string>
|
||||
<string name="linux_device_path_for_example_dev_i2c_1">Linux 设备路径,例如 /dev/i2c-1。</string>
|
||||
<string name="loading_image">正在加载图片</string>
|
||||
<string name="local_offline">本地离线</string>
|
||||
<string name="localonlyhotspot">LocalOnlyHotspot</string>
|
||||
<string name="location">位置</string>
|
||||
<string name="longest_height">较长边</string>
|
||||
<string name="looking_for_your_paired_iphone">正在查找已配对的 iPhone…</string>
|
||||
<string name="made_possible_by_open_source">开源项目鸣谢</string>
|
||||
<string name="make_diplay_feel_right_for_your_car">按需调整 DiPlay 设置。</string>
|
||||
<string name="manual_hotspot">手动热点</string>
|
||||
<string name="manual_mode_match_the_cluster_theme_here_the_map_cannot_fo">手动模式:在此匹配仪表盘主题。没有使用访问权限时,地图无法跟随卡片显示状态。</string>
|
||||
<string name="manufacturer">制造商</string>
|
||||
<string name="mfi_authentication_ready">MFi 认证已就绪</string>
|
||||
<string name="mfi_certificate_signing_target">MFi 证书与签名目标</string>
|
||||
<string name="model">型号</string>
|
||||
<string name="music_buffer">音乐缓冲</string>
|
||||
<string name="resolution_native">原生</string>
|
||||
<string name="navigation_on_hud_and_instrument_cluster">在 HUD 和仪表盘显示导航</string>
|
||||
<string name="navigation_stream_type">导航音频流类型</string>
|
||||
<string name="nearby_devices">附近的设备</string>
|
||||
<string name="nearby_devices_connects_your_iphone_microphone_enables_sir">“附近的设备”权限用于连接 iPhone;麦克风权限用于 Siri 和通话。较旧的 Android 版本还需要位置权限来设置无线连接。USB 模式可能会请求建立本地 VPN 连接。</string>
|
||||
<string name="nothing_is_sent_automatically_protocol_payloads_and_creden">报告不会自动发送,不包含协议数据和凭据。</string>
|
||||
<string name="oem_label">OEM 标签</string>
|
||||
<string name="on_your_iphone_open_settings_bluetooth_and_pair_with_the_c">在 iPhone 上打开“设置 → 蓝牙”并与车机配对。然后返回 DiPlay,点击“连接手机”。</string>
|
||||
<string name="one_time_setup_on_this_car">在此车机上一次性设置</string>
|
||||
<string name="open">开放</string>
|
||||
<string name="open_after_the_car_starts">车机启动后打开</string>
|
||||
<string name="open_bluetooth">打开蓝牙</string>
|
||||
<string name="open_car_hotspot_settings">打开车机热点设置</string>
|
||||
<string name="open_car_settings">打开车机设置</string>
|
||||
<string name="open_car_wi_fi_settings">打开车机 Wi-Fi 设置</string>
|
||||
<string name="open_carplay">打开 CarPlay</string>
|
||||
<string name="open_connection_setup">打开连接设置</string>
|
||||
<string name="open_this_setting_from_your_car_s_settings_app">请在车机的设置应用中打开此设置。</string>
|
||||
<string name="opening_carplay">正在打开 CarPlay…</string>
|
||||
<string name="opening_usb_data_paths">正在打开 USB 数据通道</string>
|
||||
<string name="pair_another">配对其他设备</string>
|
||||
<string name="pair_your_iphone">配对 iPhone</string>
|
||||
<string name="pair_your_iphone_with_the_car_s_bluetooth_keep_wi_fi_on_an">在车机蓝牙设置中配对 iPhone,保持 Wi-Fi 开启,并在 iPhone 上允许 CarPlay。请关闭其他手机投屏应用。\n\n如果之前的投屏应用残留了连接,请先重置下方的 CarPlay Wi-Fi,再重新连接。车机正常的互联网 Wi-Fi 不受影响。</string>
|
||||
<string name="paired_device">已配对设备</string>
|
||||
<string name="pairing_with_iphone">正在与 iPhone 配对</string>
|
||||
<string name="password_must_be_empty_when_security_is_open">安全类型为“开放”时,密码必须留空</string>
|
||||
<string name="permissions_and_connection_help">权限与连接帮助</string>
|
||||
<string name="physical_length">物理长度</string>
|
||||
<string name="physical_size_basis">物理尺寸依据</string>
|
||||
<string name="place_carplay_s_controls_closer_to_the_driver">将 CarPlay 控件移至更靠近驾驶员的一侧。</string>
|
||||
<string name="plug_your_iphone_into_a_usb_data_port_allow_carplay_when_y">将 iPhone 连接到支持数据传输的 USB 接口。\n手机出现提示时允许使用 CarPlay。</string>
|
||||
<string name="prefer_a_cable">想用数据线?</string>
|
||||
<string name="preparing_mfi_authentication">正在准备 MFi 认证</string>
|
||||
<string name="ready">就绪</string>
|
||||
<string name="ready_when_you_are">一切就绪</string>
|
||||
<string name="receiver_based_on_xcertplay_licensed_under_gpl_3_0_diplay">接收器基于采用 GPL-3.0 许可的 xcertplay。DiPlay 界面沿用采用 AGPL-3.0 许可的 DiAuto 设计。\n\n项目包含 AndroidX、Bouncy Castle、JmDNS 和 SLF4J。本版本附有源代码和许可声明。\n\nCarPlay 和 CarPlay 图标归 Apple Inc. 所有。DiPlay 是独立项目。</string>
|
||||
<string name="reconnecting_to_your_iphone">正在重新连接 iPhone…</string>
|
||||
<string name="remote">远程</string>
|
||||
<string name="remote_server_address_contains_u_0000">远程服务器地址包含 U+0000</string>
|
||||
<string name="remote_server_address_is_required">必须填写远程服务器地址</string>
|
||||
<string name="remote_server_address_must_start_with_http_or_https">远程服务器地址必须以 http:// 或 https:// 开头</string>
|
||||
<string name="remote_token_contains_u_0000">远程令牌包含 U+0000</string>
|
||||
<string name="report_android_location_to_the_iphone">向 iPhone 报告 Android 位置</string>
|
||||
<string name="report_location_to_iphone">向 iPhone 报告位置</string>
|
||||
<string name="report_saved_open_it_from_your_file_manager_to_share_it">报告已保存。在文件管理器中打开即可分享。</string>
|
||||
<string name="reports_save_to_downloads_diplay">报告将保存到 Downloads/DiPlay。</string>
|
||||
<string name="requesting_iphone_usb_permission">正在请求 iPhone USB 权限</string>
|
||||
<string name="requesting_mfi_usb_permission">正在请求 MFi USB 权限</string>
|
||||
<string name="reset">重置</string>
|
||||
<string name="reset_and_connect">重置并连接</string>
|
||||
<string name="reset_car_marker_to_centre">将车辆标记重置到居中</string>
|
||||
<string name="reset_carplay_wi_fi">重置 CarPlay Wi-Fi</string>
|
||||
<string name="reset_carplay_wi_fi_2">重置 CarPlay Wi-Fi?</string>
|
||||
<string name="resolution">分辨率</string>
|
||||
<string name="return_from_car_settings_to_diplay_then_connect_accept_the">从车机设置返回 DiPlay,然后连接。在 iPhone 上接受 CarPlay 提示。无需车机流量套餐;移动数据可用性取决于手机的网络设置。</string>
|
||||
<string name="review_app_permissions">查看应用权限</string>
|
||||
<string name="right_hand_drive">右舵</string>
|
||||
<string name="running">运行中</string>
|
||||
<string name="s_0_3x">0.3x</string>
|
||||
<string name="s_1000_ms_most_stable">1000 毫秒 · 更稳定</string>
|
||||
<string name="s_1_0x">1.0x</string>
|
||||
<string name="s_1_choose_your_connection">1 · 选择连接方式</string>
|
||||
<string name="s_1_connect_a_computer_with_adb_installed_to_the_car_using">1. 用装有 ADB 的电脑,通过现有的 USB 或无线调试连接连接到车机。如有调试授权提示请批准。\n\n2. 在电脑终端中运行此命令:</string>
|
||||
<string name="s_1_open_car_hotspot_settings_turn_the_hotspot_on_and_sele">1. 打开车机热点设置,开启热点,如有 5 GHz 请选择。\n2. 在下方准确复制热点名称和密码。\n3. 连接时保持车机热点开启。DiPlay 通过蓝牙发送热点信息,iPhone 会自动加入。</string>
|
||||
<string name="s_2_4_ghz">2.4 GHz</string>
|
||||
<string name="s_2_pair_your_iphone">2 · 配对你的 iPhone</string>
|
||||
<string name="s_300_ms_default">300 毫秒 · 默认</string>
|
||||
<string name="s_30_fps_lighter_load">30 帧/秒 · 减轻负载</string>
|
||||
<string name="s_3_connect">3 · 连接</string>
|
||||
<string name="s_3_tap_check_and_enable_below_this_enables_the_cluster_ma">3. 点击下方“检查并启用”。这将启用仪表盘地图和自动主题跟随。正在进行的 CarPlay 会话会重新连接一次,之后即可断开电脑。</string>
|
||||
<string name="s_500_ms">500 毫秒</string>
|
||||
<string name="s_5_ghz">5 GHz</string>
|
||||
<string name="s_60_fps_smoother_motion">60 帧/秒 · 更流畅</string>
|
||||
<string name="s_60_lightest_load" formatted="false">60% · 最低负载</string>
|
||||
<string name="s_80_lighter_load" formatted="false">80% · 减轻负载</string>
|
||||
<string name="safe_area">安全区域</string>
|
||||
<string name="safe_area_waiting_for_activity_size">安全区域:正在等待活动窗口尺寸</string>
|
||||
<string name="save">保存</string>
|
||||
<string name="save_1_1">保存 1:1 图片</string>
|
||||
<string name="save_and_reconnect">保存并重新连接</string>
|
||||
<string name="save_details">保存详情</string>
|
||||
<string name="save_diagnostic_report">保存诊断报告</string>
|
||||
<string name="save_hotspot_details_and_use_this_mode">保存热点信息并使用此模式</string>
|
||||
<string name="save_the_name_and_password_from_the_car_s_hotspot_settings">请先保存车机热点设置中的名称和密码</string>
|
||||
<string name="save_your_hotspot_details_in_connection_setup_first">请先在“连接设置”中保存热点信息</string>
|
||||
<string name="saved_for_your_next_connection">已保存,将在下次连接时生效</string>
|
||||
<string name="saving_report">正在保存报告…</string>
|
||||
<string name="security">安全类型</string>
|
||||
<string name="selecting_carplay_configuration">正在选择 CarPlay 配置</string>
|
||||
<string name="sends_precise_android_location_as_carplay_gps_data_when_th">iPhone 请求时,将 Android 精确位置作为 CarPlay GPS 数据发送。</string>
|
||||
<string name="server_address">服务器地址</string>
|
||||
<string name="set">设置</string>
|
||||
<string name="set_up_once_your_details_stay_saved_for_the_next_drive_cha">只需设置一次,信息会保存供下次驾驶使用。更改将在下次连接时生效。</string>
|
||||
<string name="settings">设置</string>
|
||||
<string name="setup_needs_attention">设置需要处理</string>
|
||||
<string name="share">分享</string>
|
||||
<string name="show_on_screen_debug_logs">在屏幕上显示调试日志</string>
|
||||
<string name="show_password">显示密码</string>
|
||||
<string name="show_phone_navigation_arrows_distance_and_street_names_on">在支持的比亚迪显示屏上显示手机导航箭头、距离和道路名称。不同车型的兼容性有所差异。</string>
|
||||
<string name="show_the_side_map_only_when_its_card_is_open_and_switch_to">仅在地图卡片展开时显示侧方地图,并在“地图主题”中切换为完整地图。更改主题或卡片不会中断 CarPlay 连接。</string>
|
||||
<string name="shows_the_iphone_s_cluster_map_on_the_instrument_cluster_c">在仪表盘上显示 iPhone 的地图。可在方向盘菜单中选择“小”或“全屏导航”。</string>
|
||||
<string name="start_carplay_automatically_after_device_boot">设备启动后自动启动 CarPlay</string>
|
||||
<string name="starting">正在启动</string>
|
||||
<string name="starting_airplay_service">正在启动 AirPlay 服务</string>
|
||||
<string name="starting_wireless_hotspot">正在启动无线热点</string>
|
||||
<string name="startup">启动</string>
|
||||
<string name="still_waiting_for_usage_access_check_that_the_command_ran">仍在等待使用访问权限。请确认命令已在本车机上成功运行,然后重试。</string>
|
||||
<string name="tap_a_number_to_test_14_driver_speaker_on_byd">点按数字测试。14 = 比亚迪主驾扬声器。</string>
|
||||
<string name="the_head_unit_couldn_t_start_carplay_wi_fi_check_wi_fi_and">车机无法启动 CarPlay Wi-Fi。请检查 Wi-Fi 并关闭其他投屏应用,正在重试…</string>
|
||||
<string name="this_ends_the_existing_wi_fi_direct_connection_including_o">这会结束现有的 Wi-Fi Direct 连接,包括重新安装后遗留的连接。请先关闭其他投屏应用。车机的互联网 Wi-Fi 不受影响。</string>
|
||||
<string name="this_head_unit_cannot_use_the_smaller_size_at_this_resolut">此车机在当前分辨率下无法使用更小的尺寸,将使用默认尺寸。</string>
|
||||
<string name="this_head_unit_could_not_open_a_save_location_please_try_s">车机无法打开保存位置,请重试保存到 Downloads。</string>
|
||||
<string name="this_head_unit_does_not_support_wi_fi_direct">此车机不支持 Wi-Fi Direct。</string>
|
||||
<string name="this_head_unit_has_no_available_file_picker_to_save_the_re">此车机没有可用于保存报告的文件选择器。</string>
|
||||
<string name="this_head_unit_may_not_support_wireless_carplay_try_a_usb">此车机可能不支持无线 CarPlay,请尝试 USB 连接。</string>
|
||||
<string name="token_optional">令牌(可选)</string>
|
||||
<string name="transport_error_reconnecting">传输错误;正在重新连接</string>
|
||||
<string name="turn_on_bluetooth">打开蓝牙</string>
|
||||
<string name="turn_on_wi_fi_in_the_head_unit_s_settings_to_connect">请在车机设置中打开 Wi-Fi 后再连接。</string>
|
||||
<string name="turn_the_car_s_wi_fi_switch_on_allow_location_nearby_devic">打开车机的 Wi-Fi 开关。如提示请允许位置/附近的设备权限,并在 Android 询问时启用位置。如果播放卡顿,请尝试使用 5 GHz 的内置车机热点。</string>
|
||||
<string name="usage_access_enabled">使用访问权限:已启用</string>
|
||||
<string name="usage_access_lets_diplay_follow_the_instrument_theme_and_m">使用访问权限让 DiPlay 跟随仪表盘主题和地图卡片。仅在本地处理 BYD 仪表盘活动事件。本车机没有可用的权限设置页面。</string>
|
||||
<string name="usage_access_setup_needed_for_automatic_mode">使用访问权限:自动模式需要设置</string>
|
||||
<string name="usb_ch341">USB/CH341</string>
|
||||
<string name="use_a_usb_data_cable_and_the_car_s_usb_data_port_unlock_yo">使用 USB 数据线连接车机的 USB 数据接口。解锁 iPhone 并允许 CarPlay。无需设置热点。</string>
|
||||
<string name="use_a_usb_data_cable_and_unlock_your_iphone_allow_trust_an">请使用 USB 数据线并解锁 iPhone。\niPhone 出现提示时允许“信任”和使用 CarPlay。</string>
|
||||
<string name="use_hevc_leave_off_for_the_widest_head_unit_compatibility">使用 HEVC。关闭后可兼容更多车机。</string>
|
||||
<string name="use_software_hevc_decoder">使用 HEVC 软件解码器</string>
|
||||
<string name="use_usage_content_type_routing_instead_of_stream_type">使用 usage / content-type 路由代替流类型</string>
|
||||
<string name="use_your_last_connection_type_and_selected_iphone">使用上次的连接方式和已选 iPhone。</string>
|
||||
<string name="vpn_consent_was_denied">VPN 授权被拒绝</string>
|
||||
<string name="waiting_for_iphone_over_usb">正在等待 USB 连接的 iPhone</string>
|
||||
<string name="waiting_for_mfi_coprocessor">正在等待 MFi 协处理器</string>
|
||||
<string name="waiting_for_paired_iphone">正在等待已配对的 iPhone</string>
|
||||
<string name="wi_fi_direct_is_still_busy_close_the_other_projection_app">Wi-Fi Direct 仍被占用。请关闭其他投屏应用后重试。</string>
|
||||
<string name="wi_fi_p2p_5_ghz">Wi-Fi P2P(5 GHz)</string>
|
||||
<string name="wi_fi_session">Wi-Fi 会话</string>
|
||||
<string name="widest_width">较宽边</string>
|
||||
<string name="window">窗口</string>
|
||||
<string name="wireless_carplay">无线 CarPlay</string>
|
||||
<string name="wireless_carplay_2">无线 CarPlay</string>
|
||||
<string name="wireless_carplay_active">无线 CarPlay 已启用</string>
|
||||
<string name="wireless_carplay_control_running">无线 CarPlay 控制通道运行中</string>
|
||||
<string name="wireless_carplay_transport">无线 CarPlay 连接</string>
|
||||
<string name="wireless_connection_help">无线连接帮助</string>
|
||||
<string name="wireless_hotspot_off">无线热点:关闭</string>
|
||||
<string name="wireless_permissions">无线连接权限</string>
|
||||
<string name="wpa2">WPA2</string>
|
||||
<string name="wpa2_wpa3_password_must_be_8_63_characters">WPA2/WPA3 密码长度必须为 8–63 个字符</string>
|
||||
<string name="wpa3">WPA3</string>
|
||||
<string name="wpa3_transition">WPA3 过渡模式</string>
|
||||
<string name="your_drive_your_way">按你的习惯设置。</string>
|
||||
<string name="your_iphone_isn_t_available_unlock_it_and_check_bluetooth">暂时找不到 iPhone。请解锁手机并检查蓝牙。</string>
|
||||
<string name="your_maps_music_and_conversations_carplay_right_here_on_yo">地图、音乐与通话,\n在车机屏幕上畅享 CarPlay。</string>
|
||||
<string name="your_phone_your_drive">你的手机,畅享旅程。</string>
|
||||
<string name="your_report_was_saved_to_the_selected_location">报告已保存到所选位置。</string>
|
||||
</resources>
|
||||
@@ -1,4 +1,19 @@
|
||||
<resources>
|
||||
<string name="msg_car_hotspot_off">The car hotspot “%1$s” is off. Turn it on in the car settings before connecting.</string>
|
||||
<string name="home_public_preview">PUBLIC PREVIEW ·\u0020\u0020</string>
|
||||
<string name="choose_iphone_prefix">Choose iPhone ·\u0020</string>
|
||||
<string name="audio_saved_value">Saved: %1$d</string>
|
||||
<string name="about_public_preview_prefix">Public preview ·\u0020</string>
|
||||
<string name="msg_car_hotspot_connect">DiPlay connects through the car hotspot “%1$s”. Turn it on in the car settings, then connect.</string>
|
||||
<string name="edit_saved_hotspot_prefix">Edit saved hotspot ·\u0020</string>
|
||||
<string name="cluster_adb_multi_device">If ADB lists several devices, use adb -s <car-device-ID> shell appops set %1$s GET_USAGE_STATS allow. Find the ID with adb devices.</string>
|
||||
<string name="status_ready_for_prefix">Ready for\u0020</string>
|
||||
<string name="audio_stream_unavailable">Stream type %1$d is unavailable here (state=%2$s)</string>
|
||||
<string name="resolution_handshake_prefix">Handshake resolution:\u0020</string>
|
||||
<string name="safe_area_full_screen_at">Safe area: full screen at\u0020</string>
|
||||
<string name="safe_area_prefix">Safe area:\u0020</string>
|
||||
<string name="settings_android9_compat">The following settings are unavailable and hidden on Android 9 (API 28):\n• Wi-Fi P2P (5 GHz) — LocalOnlyHotspot is used instead.\n• HEVC software decoder — hardware decoding is used instead.</string>
|
||||
<string name="settings_mfi_address_hint">Address must start with http:// or https://. Token is optional and sent as an Authorization bearer token.</string>
|
||||
<string name="app_name">DiPlay</string>
|
||||
<string name="language_section_title">Language</string>
|
||||
<string name="language_app_language">App language</string>
|
||||
@@ -6,4 +21,320 @@
|
||||
<string name="language_hint">Choose a language for DiPlay. System default follows the device language.</string>
|
||||
<string name="language_apply">Apply</string>
|
||||
<string name="common_cancel">Cancel</string>
|
||||
<string name="a_familiar_drive">A familiar drive.</string>
|
||||
<string name="a_previous_wi_fi_direct_connection_is_still_running_reset">A previous Wi-Fi Direct connection is still running. Reset it to connect.</string>
|
||||
<string name="about">About</string>
|
||||
<string name="about_diplay">About DiPlay</string>
|
||||
<string name="active">Active</string>
|
||||
<string name="advanced_audio_channel_mapping">Advanced audio channel mapping</string>
|
||||
<string name="airplay_icon">AirPlay icon</string>
|
||||
<string name="allow_carplay_ui_outside_the_safe_area">Allow CarPlay UI outside the safe area</string>
|
||||
<string name="allow_nearby_devices_and_on_older_android_versions_locatio">Allow Nearby devices and, on older Android versions, Location before resetting CarPlay Wi-Fi.</string>
|
||||
<string name="allow_nearby_devices_for_diplay_in_the_head_unit_s_app_per">Allow Nearby devices for DiPlay in the head unit’s app permissions.</string>
|
||||
<string name="allow_nearby_devices_so_diplay_can_connect_to_your_paired">Allow Nearby devices so DiPlay can connect to your paired iPhone.</string>
|
||||
<string name="allow_precise_location_for_diplay_in_the_head_unit_s_app_p">Allow precise Location for DiPlay in the head unit’s app permissions.</string>
|
||||
<string name="allow_the_connection_permission_to_continue">Allow the connection permission to continue</string>
|
||||
<string name="an_independent_carplay_receiver_for_android_head_units_wir">An independent CarPlay receiver for Android head units. Wired and wireless connections run on the head unit, with local authentication. A standard iPhone can connect without a jailbreak, Mac, dongle or sign-in.\n\nThis preview uses an experimental accessory identity. Compatibility with every iPhone and head unit is still being tested. It is not an Apple-certified product.</string>
|
||||
<string name="android_9_compatibility">Android 9 compatibility</string>
|
||||
<string name="app_permissions">App permissions</string>
|
||||
<string name="app_settings">App settings</string>
|
||||
<string name="apply_and_reconnect">Apply and reconnect</string>
|
||||
<string name="apply_reconnects_carplay_for_size_resolution_music_buffer">Apply reconnects CarPlay for size, resolution, music buffer and frame rate. Other changes apply to your next connection.</string>
|
||||
<string name="audio">Audio</string>
|
||||
<string name="audio_routing">Audio routing</string>
|
||||
<string name="auto">Auto</string>
|
||||
<string name="auto_start_on_boot">Auto-start on boot</string>
|
||||
<string name="automatic_cluster_map_setup">Automatic cluster map setup</string>
|
||||
<string name="automatic_connection">Automatic connection</string>
|
||||
<string name="automatic_map_enabled_open_the_cluster_map_card_or_select">Automatic map enabled. Open the cluster map card or select Map theme.</string>
|
||||
<string name="automatic_map_setup_adb">Automatic map setup · ADB</string>
|
||||
<string name="availability_depends_on_your_head_unit_s_startup_settings">Availability depends on your head unit’s startup settings.</string>
|
||||
<string name="back">Back</string>
|
||||
<string name="back_to_diplay">Back to DiPlay</string>
|
||||
<string name="band">Band</string>
|
||||
<string name="bluetooth_settings">Bluetooth settings</string>
|
||||
<string name="byd_navigation">BYD navigation</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="car_home">Car home</string>
|
||||
<string name="car_hotspot_details">Car hotspot details</string>
|
||||
<string name="car_hotspot_is_off">Car hotspot is off</string>
|
||||
<string name="car_marker_horizontal">Car marker · horizontal</string>
|
||||
<string name="car_marker_vertical">Car marker · vertical</string>
|
||||
<string name="carplay">CarPlay</string>
|
||||
<string name="carplay_at_home_in_your_car">CarPlay, at home in your car.</string>
|
||||
<string name="carplay_connected">CarPlay connected</string>
|
||||
<string name="carplay_control_running">CarPlay control running</string>
|
||||
<string name="carplay_control_window_ended">CarPlay control window ended</string>
|
||||
<string name="carplay_icon">CarPlay icon</string>
|
||||
<string name="carplay_map_on_instrument_cluster_experimental">CarPlay map on instrument cluster · experimental</string>
|
||||
<string name="carplay_service_already_running">CarPlay service already running</string>
|
||||
<string name="carplay_session_already_running">CarPlay session already running</string>
|
||||
<string name="carplay_session_ended_reconnecting">CarPlay session ended; reconnecting</string>
|
||||
<string name="carplay_settings">CarPlay settings</string>
|
||||
<string name="carplay_size">CarPlay size</string>
|
||||
<string name="changes_the_size_of_carplay_icons_and_text_applying_a_size">Changes the size of CarPlay icons and text. Applying a size reconnects CarPlay.</string>
|
||||
<string name="channel_0_auto">Channel (0 = auto)</string>
|
||||
<string name="channel_is_not_valid_for_the_selected_band">Channel is not valid for the selected band</string>
|
||||
<string name="channel_must_be_0_or_1_196">Channel must be 0 or 1-196</string>
|
||||
<string name="check_and_enable">Check and enable</string>
|
||||
<string name="check_that_storage_is_available_or_choose_another_save_loc">Check that storage is available, or choose another save location.</string>
|
||||
<string name="choose_how_to_connect_follow_the_setup_steps_and_save_your">Choose how to connect, follow the setup steps and save your car hotspot details.</string>
|
||||
<string name="choose_image">Choose image</string>
|
||||
<string name="choose_iphone">Choose iPhone</string>
|
||||
<string name="choose_location">Choose location</string>
|
||||
<string name="choose_save_location">Choose save location</string>
|
||||
<string name="choose_where_to_save_your_report">Choose where to save your report.\u0020</string>
|
||||
<string name="choose_your_iphone">Choose your iPhone</string>
|
||||
<string name="close">Close</string>
|
||||
<string name="cluster_map_size">Cluster map size</string>
|
||||
<string name="connect">Connect</string>
|
||||
<string name="connect_phone">Connect phone</string>
|
||||
<string name="connect_when_diplay_opens">Connect when DiPlay opens</string>
|
||||
<string name="connect_with_usb">Connect with USB</string>
|
||||
<string name="connect_your_iphone_with_a_usb_cable">Connect your iPhone with a USB cable</string>
|
||||
<string name="connecting_bluetooth">Connecting Bluetooth</string>
|
||||
<string name="connecting_iap2_control">Connecting iAP2 control</string>
|
||||
<string name="connecting_to_your_iphone">Connecting to your iPhone…</string>
|
||||
<string name="connection">Connection</string>
|
||||
<string name="connection_interrupted_retrying">Connection interrupted. Retrying…</string>
|
||||
<string name="connection_setup">Connection setup</string>
|
||||
<string name="copied_to_the_car_clipboard_run_the_command_on_your_comput">Copied to the car clipboard. Run the command on your computer.</string>
|
||||
<string name="copy_command">Copy command</string>
|
||||
<string name="copy_these_from_the_car_s_hotspot_settings_use_5_ghz_if_av">Copy these from the car’s hotspot settings. Use 5 GHz if available. Saving here does not change the car’s hotspot.</string>
|
||||
<string name="could_not_decode_image">Could not decode image</string>
|
||||
<string name="could_not_encode_image">Could not encode image</string>
|
||||
<string name="could_not_reset_wi_fi_direct_close_the_other_projection_ap">Could not reset Wi-Fi Direct. Close the other projection app and try again.</string>
|
||||
<string name="could_not_save_image">Could not save image</string>
|
||||
<string name="could_not_save_the_report">Could not save the report</string>
|
||||
<string name="could_not_start_carplay_return_to_diplay_and_check_app_per">Could not start CarPlay. Return to DiPlay and check app permissions.</string>
|
||||
<string name="custom_1_1_icon">Custom 1:1 icon</string>
|
||||
<string name="debug_logs">Debug logs</string>
|
||||
<string name="default_icon">Default icon</string>
|
||||
<string name="default_placeholder_icon">Default placeholder icon</string>
|
||||
<string name="diagnostic_report_saved">Diagnostic report saved</string>
|
||||
<string name="diagnostics">Diagnostics</string>
|
||||
<string name="diplay">DiPlay</string>
|
||||
<string name="discard_changes_and_exit_settings">Discard changes and exit settings</string>
|
||||
<string name="disconnect">Disconnect</string>
|
||||
<string name="discovering_iphone">Discovering iPhone</string>
|
||||
<string name="display_and_performance">Display and performance</string>
|
||||
<string name="display_video">Display & video</string>
|
||||
<string name="done">Done</string>
|
||||
<string name="drag_to_move_pinch_to_zoom">Drag to move, pinch to zoom</string>
|
||||
<string name="draw_outside_safe_area">Draw outside safe area</string>
|
||||
<string name="driving_side">Driving side</string>
|
||||
<string name="efficient_video">Efficient video</string>
|
||||
<string name="enable_the_car_s_bluetooth_and_pair_your_iphone_first">Enable the car’s Bluetooth and pair your iPhone first.</string>
|
||||
<string name="error">Error</string>
|
||||
<string name="exit_application">EXIT APPLICATION</string>
|
||||
<string name="finish_setup_save_your_hotspot_details_to_use_this_mode">Finish setup · Save your hotspot details to use this mode.</string>
|
||||
<string name="follow_instrument_theme_and_map_card">Follow instrument theme and map card</string>
|
||||
<string name="frame_rate">Frame rate</string>
|
||||
<string name="full_screen">Full screen</string>
|
||||
<string name="fullscreen">Fullscreen</string>
|
||||
<string name="getting_carplay_ready">Getting CarPlay ready…</string>
|
||||
<string name="got_it">Got it</string>
|
||||
<string name="handshake_resolution_waiting_for_display">Handshake resolution: waiting for display</string>
|
||||
<string name="hevc_h_265_video_transport">HEVC H.265 video transport</string>
|
||||
<string name="hevc_software_decoder">HEVC software decoder</string>
|
||||
<string name="hide_bottom_bar">Hide bottom bar</string>
|
||||
<string name="hide_keyboard">Hide keyboard</string>
|
||||
<string name="hide_the_car_s_system_bars_while_carplay_is_open">Hide the car’s system bars while CarPlay is open.</string>
|
||||
<string name="hide_the_navigation_bar">Hide the navigation bar</string>
|
||||
<string name="hide_the_status_bar">Hide the status bar</string>
|
||||
<string name="hide_top_bar">Hide top bar</string>
|
||||
<string name="hotspot_name">Hotspot name</string>
|
||||
<string name="hotspot_password">Hotspot password</string>
|
||||
<string name="hotspot_password_contains_u_0000">Hotspot password contains U+0000</string>
|
||||
<string name="hotspot_setup">Hotspot setup</string>
|
||||
<string name="hotspot_ssid">Hotspot SSID</string>
|
||||
<string name="hotspot_ssid_contains_u_0000">Hotspot SSID contains U+0000</string>
|
||||
<string name="hotspot_ssid_is_required">Hotspot SSID is required</string>
|
||||
<string name="hotspot_ssid_must_be_at_most_32_utf_8_bytes">Hotspot SSID must be at most 32 UTF-8 bytes</string>
|
||||
<string name="hotspot_status">Hotspot status</string>
|
||||
<string name="i2c">I2C</string>
|
||||
<string name="i2c_device">I2C device</string>
|
||||
<string name="i2c_device_path_contains_u_0000">I2C device path contains U+0000</string>
|
||||
<string name="i2c_device_path_is_required">I2C device path is required</string>
|
||||
<string name="identity_appearance">Identity & appearance</string>
|
||||
<string name="image_is_not_ready">Image is not ready</string>
|
||||
<string name="in_carplay_swipe_down_with_three_fingers_to_open_diplay_se">In CarPlay, swipe down with three fingers to open DiPlay settings.</string>
|
||||
<string name="instrument_contrast">Instrument contrast</string>
|
||||
<string name="instrument_theme">Instrument theme</string>
|
||||
<string name="keep_bluetooth_and_wi_fi_on_your_iphone_pair_with_the_car">Keep Bluetooth and Wi-Fi on your iPhone. Pair with the car’s Bluetooth, then select your iPhone here. Allow Nearby devices when asked.</string>
|
||||
<string name="keep_your_iphone_nearby_with_bluetooth_and_wi_fi_on_allow">Keep your iPhone nearby with Bluetooth and Wi-Fi on.\nAllow CarPlay if your iPhone asks.</string>
|
||||
<string name="later">Later</string>
|
||||
<string name="left_hand_drive">Left-hand drive</string>
|
||||
<string name="linux_device_path_for_example_dev_i2c_1">Linux device path, for example /dev/i2c-1.</string>
|
||||
<string name="loading_image">Loading image</string>
|
||||
<string name="local_offline">Local offline</string>
|
||||
<string name="localonlyhotspot">LocalOnlyHotspot</string>
|
||||
<string name="location">Location</string>
|
||||
<string name="longest_height">Longest height</string>
|
||||
<string name="looking_for_your_paired_iphone">Looking for your paired iPhone…</string>
|
||||
<string name="made_possible_by_open_source">Made possible by open source</string>
|
||||
<string name="make_diplay_feel_right_for_your_car">Make DiPlay feel right for your car.</string>
|
||||
<string name="manual_hotspot">Manual hotspot</string>
|
||||
<string name="manual_mode_match_the_cluster_theme_here_the_map_cannot_fo">Manual mode: match the cluster theme here. The map cannot follow card visibility without Usage Access.</string>
|
||||
<string name="manufacturer">Manufacturer</string>
|
||||
<string name="mfi_authentication_ready">MFi authentication ready</string>
|
||||
<string name="mfi_certificate_signing_target">MFI certificate & signing target</string>
|
||||
<string name="model">Model</string>
|
||||
<string name="music_buffer">Music buffer</string>
|
||||
<string name="resolution_native">Native</string>
|
||||
<string name="navigation_on_hud_and_instrument_cluster">Navigation on HUD and instrument cluster</string>
|
||||
<string name="navigation_stream_type">Navigation stream type</string>
|
||||
<string name="nearby_devices">Nearby devices</string>
|
||||
<string name="nearby_devices_connects_your_iphone_microphone_enables_sir">Nearby devices connects your iPhone. Microphone enables Siri and calls. Older Android versions also require Location for wireless setup. USB mode may ask for a local VPN connection.</string>
|
||||
<string name="nothing_is_sent_automatically_protocol_payloads_and_creden">Nothing is sent automatically. Protocol payloads and credentials are excluded.</string>
|
||||
<string name="oem_label">OEM label</string>
|
||||
<string name="on_your_iphone_open_settings_bluetooth_and_pair_with_the_c">On your iPhone, open Settings → Bluetooth and pair with the car. Then return to DiPlay and choose Connect phone.</string>
|
||||
<string name="one_time_setup_on_this_car">One-time setup on this car</string>
|
||||
<string name="open">Open</string>
|
||||
<string name="open_after_the_car_starts">Open after the car starts</string>
|
||||
<string name="open_bluetooth">Open Bluetooth</string>
|
||||
<string name="open_car_hotspot_settings">Open car hotspot settings</string>
|
||||
<string name="open_car_settings">Open car settings</string>
|
||||
<string name="open_car_wi_fi_settings">Open car Wi-Fi settings</string>
|
||||
<string name="open_carplay">Open CarPlay</string>
|
||||
<string name="open_connection_setup">Open connection setup</string>
|
||||
<string name="open_this_setting_from_your_car_s_settings_app">Open this setting from your car’s Settings app.</string>
|
||||
<string name="opening_carplay">Opening CarPlay…</string>
|
||||
<string name="opening_usb_data_paths">Opening USB data paths</string>
|
||||
<string name="pair_another">Pair another</string>
|
||||
<string name="pair_your_iphone">Pair your iPhone</string>
|
||||
<string name="pair_your_iphone_with_the_car_s_bluetooth_keep_wi_fi_on_an">Pair your iPhone with the car’s Bluetooth, keep Wi-Fi on, and allow CarPlay on the iPhone. Close any other phone-projection app.\n\nIf a previous projection app left its connection running, reset CarPlay Wi-Fi below and connect again. Your car’s normal internet Wi-Fi stays on.</string>
|
||||
<string name="paired_device">Paired device</string>
|
||||
<string name="pairing_with_iphone">Pairing with iPhone</string>
|
||||
<string name="password_must_be_empty_when_security_is_open">Password must be empty when security is Open</string>
|
||||
<string name="permissions_and_connection_help">Permissions and connection help</string>
|
||||
<string name="physical_length">Physical length</string>
|
||||
<string name="physical_size_basis">Physical size basis</string>
|
||||
<string name="place_carplay_s_controls_closer_to_the_driver">Place CarPlay’s controls closer to the driver.</string>
|
||||
<string name="plug_your_iphone_into_a_usb_data_port_allow_carplay_when_y">Plug your iPhone into a USB data port.\nAllow CarPlay when your iPhone asks.</string>
|
||||
<string name="prefer_a_cable">Prefer a cable?</string>
|
||||
<string name="preparing_mfi_authentication">Preparing MFi authentication</string>
|
||||
<string name="ready">Ready</string>
|
||||
<string name="ready_when_you_are">Ready when you are</string>
|
||||
<string name="receiver_based_on_xcertplay_licensed_under_gpl_3_0_diplay">Receiver based on xcertplay, licensed under GPL-3.0. DiPlay’s interface follows DiAuto’s design, licensed under AGPL-3.0.\n\nIncludes AndroidX, Bouncy Castle, JmDNS and SLF4J. Source and license notices accompany this release.\n\nCarPlay and the CarPlay icon belong to Apple Inc. DiPlay is an independent project.</string>
|
||||
<string name="reconnecting_to_your_iphone">Reconnecting to your iPhone…</string>
|
||||
<string name="remote">Remote</string>
|
||||
<string name="remote_server_address_contains_u_0000">Remote server address contains U+0000</string>
|
||||
<string name="remote_server_address_is_required">Remote server address is required</string>
|
||||
<string name="remote_server_address_must_start_with_http_or_https">Remote server address must start with http:// or https://</string>
|
||||
<string name="remote_token_contains_u_0000">Remote token contains U+0000</string>
|
||||
<string name="report_android_location_to_the_iphone">Report Android location to the iPhone</string>
|
||||
<string name="report_location_to_iphone">Report location to iPhone</string>
|
||||
<string name="report_saved_open_it_from_your_file_manager_to_share_it">Report saved. Open it from your file manager to share it.</string>
|
||||
<string name="reports_save_to_downloads_diplay">Reports save to Downloads/DiPlay.\u0020</string>
|
||||
<string name="requesting_iphone_usb_permission">Requesting iPhone USB permission</string>
|
||||
<string name="requesting_mfi_usb_permission">Requesting MFi USB permission</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="reset_and_connect">Reset and connect</string>
|
||||
<string name="reset_car_marker_to_centre">Reset car marker to centre</string>
|
||||
<string name="reset_carplay_wi_fi">Reset CarPlay Wi-Fi</string>
|
||||
<string name="reset_carplay_wi_fi_2">Reset CarPlay Wi-Fi?</string>
|
||||
<string name="resolution">Resolution</string>
|
||||
<string name="return_from_car_settings_to_diplay_then_connect_accept_the">Return from car settings to DiPlay, then connect. Accept the CarPlay prompt on your iPhone. A car internet plan is not required; mobile data availability depends on your phone’s network settings.</string>
|
||||
<string name="review_app_permissions">Review app permissions</string>
|
||||
<string name="right_hand_drive">Right-hand drive</string>
|
||||
<string name="running">Running</string>
|
||||
<string name="s_0_3x">0.3x</string>
|
||||
<string name="s_1000_ms_most_stable">1000 ms · most stable</string>
|
||||
<string name="s_1_0x">1.0x</string>
|
||||
<string name="s_1_choose_your_connection">1 · Choose your connection</string>
|
||||
<string name="s_1_connect_a_computer_with_adb_installed_to_the_car_using">1. Connect a computer with ADB installed to the car using your existing USB or wireless debugging connection. Approve debugging on the car if asked.\n\n2. Run this command in the computer’s terminal:</string>
|
||||
<string name="s_1_open_car_hotspot_settings_turn_the_hotspot_on_and_sele">1. Open car hotspot settings, turn the hotspot on and select 5 GHz if available.\n2. Copy its name and password below exactly.\n3. Leave the car hotspot on when connecting. DiPlay sends the details over Bluetooth; your iPhone joins automatically.</string>
|
||||
<string name="s_2_4_ghz">2.4 GHz</string>
|
||||
<string name="s_2_pair_your_iphone">2 · Pair your iPhone</string>
|
||||
<string name="s_300_ms_default">300 ms · default</string>
|
||||
<string name="s_30_fps_lighter_load">30 fps · lighter load</string>
|
||||
<string name="s_3_connect">3 · Connect</string>
|
||||
<string name="s_3_tap_check_and_enable_below_this_enables_the_cluster_ma">3. Tap Check and enable below. This enables the cluster map and automatic theme following. An active CarPlay session reconnects once. You can then disconnect the computer.</string>
|
||||
<string name="s_500_ms">500 ms</string>
|
||||
<string name="s_5_ghz">5 GHz</string>
|
||||
<string name="s_60_fps_smoother_motion">60 fps · smoother motion</string>
|
||||
<string name="s_60_lightest_load" formatted="false">60% · lightest load</string>
|
||||
<string name="s_80_lighter_load" formatted="false">80% · lighter load</string>
|
||||
<string name="safe_area">Safe area</string>
|
||||
<string name="safe_area_waiting_for_activity_size">Safe area: waiting for activity size</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="save_1_1">Save 1:1</string>
|
||||
<string name="save_and_reconnect">Save and reconnect</string>
|
||||
<string name="save_details">Save details</string>
|
||||
<string name="save_diagnostic_report">Save diagnostic report</string>
|
||||
<string name="save_hotspot_details_and_use_this_mode">Save hotspot details and use this mode</string>
|
||||
<string name="save_the_name_and_password_from_the_car_s_hotspot_settings">Save the name and password from the car’s hotspot settings first</string>
|
||||
<string name="save_your_hotspot_details_in_connection_setup_first">Save your hotspot details in Connection setup first</string>
|
||||
<string name="saved_for_your_next_connection">Saved for your next connection</string>
|
||||
<string name="saving_report">Saving report…</string>
|
||||
<string name="security">Security</string>
|
||||
<string name="selecting_carplay_configuration">Selecting CarPlay configuration</string>
|
||||
<string name="sends_precise_android_location_as_carplay_gps_data_when_th">Sends precise Android location as CarPlay GPS data when the iPhone requests it.</string>
|
||||
<string name="server_address">Server address</string>
|
||||
<string name="set">Set</string>
|
||||
<string name="set_up_once_your_details_stay_saved_for_the_next_drive_cha">Set up once. Your details stay saved for the next drive. Changes apply to your next connection.</string>
|
||||
<string name="settings">Settings</string>
|
||||
<string name="setup_needs_attention">Setup needs attention</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="show_on_screen_debug_logs">Show on-screen debug logs</string>
|
||||
<string name="show_password">Show password</string>
|
||||
<string name="show_phone_navigation_arrows_distance_and_street_names_on">Show phone navigation arrows, distance and street names on supported BYD displays. Vehicle compatibility varies.</string>
|
||||
<string name="show_the_side_map_only_when_its_card_is_open_and_switch_to">Show the side map only when its card is open, and switch to the full map in Map theme. Theme and card changes keep CarPlay connected.</string>
|
||||
<string name="shows_the_iphone_s_cluster_map_on_the_instrument_cluster_c">Shows the iPhone\'s cluster map on the instrument cluster. Choose Small or Full screen navi in the cluster\'s steering-wheel menu.</string>
|
||||
<string name="start_carplay_automatically_after_device_boot">Start CarPlay automatically after device boot</string>
|
||||
<string name="starting">Starting</string>
|
||||
<string name="starting_airplay_service">Starting AirPlay service</string>
|
||||
<string name="starting_wireless_hotspot">Starting wireless hotspot</string>
|
||||
<string name="startup">Startup</string>
|
||||
<string name="still_waiting_for_usage_access_check_that_the_command_ran">Still waiting for Usage Access. Check that the command ran successfully for this car, then try again.</string>
|
||||
<string name="tap_a_number_to_test_14_driver_speaker_on_byd">Tap a number to test. 14 = driver speaker on BYD.</string>
|
||||
<string name="the_head_unit_couldn_t_start_carplay_wi_fi_check_wi_fi_and">The head unit couldn’t start CarPlay Wi-Fi. Check Wi-Fi and close other projection apps. Retrying…</string>
|
||||
<string name="this_ends_the_existing_wi_fi_direct_connection_including_o">This ends the existing Wi-Fi Direct connection, including one left behind after reinstalling. Close other projection apps first. Your car’s internet Wi-Fi stays on.</string>
|
||||
<string name="this_head_unit_cannot_use_the_smaller_size_at_this_resolut">This head unit cannot use the smaller size at this resolution. Using Default.</string>
|
||||
<string name="this_head_unit_could_not_open_a_save_location_please_try_s">This head unit could not open a save location. Please try saving to Downloads again.</string>
|
||||
<string name="this_head_unit_does_not_support_wi_fi_direct">This head unit does not support Wi-Fi Direct.</string>
|
||||
<string name="this_head_unit_has_no_available_file_picker_to_save_the_re">This head unit has no available file picker to save the report.</string>
|
||||
<string name="this_head_unit_may_not_support_wireless_carplay_try_a_usb">This head unit may not support wireless CarPlay. Try a USB connection.</string>
|
||||
<string name="token_optional">Token (optional)</string>
|
||||
<string name="transport_error_reconnecting">Transport error; reconnecting</string>
|
||||
<string name="turn_on_bluetooth">Turn on Bluetooth</string>
|
||||
<string name="turn_on_wi_fi_in_the_head_unit_s_settings_to_connect">Turn on Wi-Fi in the head unit’s settings to connect.</string>
|
||||
<string name="turn_the_car_s_wi_fi_switch_on_allow_location_nearby_devic">Turn the car’s Wi-Fi switch on. Allow Location / Nearby devices if requested and enable Location when Android asks. If playback stutters, try the built-in car hotspot at 5 GHz.</string>
|
||||
<string name="usage_access_enabled">Usage Access: enabled</string>
|
||||
<string name="usage_access_lets_diplay_follow_the_instrument_theme_and_m">Usage Access lets DiPlay follow the instrument theme and map card. Only BYD cluster activity events are processed locally. This car does not provide a working permission settings page.</string>
|
||||
<string name="usage_access_setup_needed_for_automatic_mode">Usage Access: setup needed for automatic mode</string>
|
||||
<string name="usb_ch341">USB/CH341</string>
|
||||
<string name="use_a_usb_data_cable_and_the_car_s_usb_data_port_unlock_yo">Use a USB data cable and the car’s USB data port. Unlock your iPhone and allow CarPlay. No hotspot setup is needed.</string>
|
||||
<string name="use_a_usb_data_cable_and_unlock_your_iphone_allow_trust_an">Use a USB data cable and unlock your iPhone.\nAllow Trust and CarPlay if your iPhone asks.</string>
|
||||
<string name="use_hevc_leave_off_for_the_widest_head_unit_compatibility">Use HEVC. Leave off for the widest head-unit compatibility.</string>
|
||||
<string name="use_software_hevc_decoder">Use software HEVC decoder</string>
|
||||
<string name="use_usage_content_type_routing_instead_of_stream_type">Use usage / content-type routing instead of stream type</string>
|
||||
<string name="use_your_last_connection_type_and_selected_iphone">Use your last connection type and selected iPhone.</string>
|
||||
<string name="vpn_consent_was_denied">VPN consent was denied</string>
|
||||
<string name="waiting_for_iphone_over_usb">Waiting for iPhone over USB</string>
|
||||
<string name="waiting_for_mfi_coprocessor">Waiting for MFi coprocessor</string>
|
||||
<string name="waiting_for_paired_iphone">Waiting for paired iPhone</string>
|
||||
<string name="wi_fi_direct_is_still_busy_close_the_other_projection_app">Wi-Fi Direct is still busy. Close the other projection app and try again.</string>
|
||||
<string name="wi_fi_p2p_5_ghz">Wi-Fi P2P (5 GHz)</string>
|
||||
<string name="wi_fi_session">Wi-Fi session</string>
|
||||
<string name="widest_width">Widest width</string>
|
||||
<string name="window">Window</string>
|
||||
<string name="wireless_carplay">WIRELESS CARPLAY</string>
|
||||
<string name="wireless_carplay_2">Wireless CarPlay</string>
|
||||
<string name="wireless_carplay_active">Wireless CarPlay active</string>
|
||||
<string name="wireless_carplay_control_running">Wireless CarPlay control running</string>
|
||||
<string name="wireless_carplay_transport">Wireless CarPlay transport</string>
|
||||
<string name="wireless_connection_help">Wireless connection help</string>
|
||||
<string name="wireless_hotspot_off">Wireless hotspot: off</string>
|
||||
<string name="wireless_permissions">Wireless permissions</string>
|
||||
<string name="wpa2">WPA2</string>
|
||||
<string name="wpa2_wpa3_password_must_be_8_63_characters">WPA2/WPA3 password must be 8-63 characters</string>
|
||||
<string name="wpa3">WPA3</string>
|
||||
<string name="wpa3_transition">WPA3 transition</string>
|
||||
<string name="your_drive_your_way">Your drive, your way.</string>
|
||||
<string name="your_iphone_isn_t_available_unlock_it_and_check_bluetooth">Your iPhone isn’t available. Unlock it and check Bluetooth.</string>
|
||||
<string name="your_maps_music_and_conversations_carplay_right_here_on_yo">Your maps, music and conversations.\nCarPlay, right here on your car display.</string>
|
||||
<string name="your_phone_your_drive">YOUR PHONE. YOUR DRIVE.</string>
|
||||
<string name="your_report_was_saved_to_the_selected_location">Your report was saved to the selected location.</string>
|
||||
</resources>
|
||||
Reference in new issue
Block a user