mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 12:56:49 +01:00
Add initial support for Shell Racing cars
- adds initial device support - can control driving forward/back/left/right - probably could be implemented further: - battery reading - device name? - lights on - fast/slow speed mode
This commit is contained in:
parent
63b1cffe2a
commit
e6411b15ab
@ -689,6 +689,10 @@
|
||||
android:name=".devices.um25.Activity.DataActivity"
|
||||
android:exported="true" />
|
||||
|
||||
<activity
|
||||
android:name=".devices.supercars.ControlActivity"
|
||||
android:exported="true" />
|
||||
|
||||
<activity
|
||||
android:name=".devices.binary_sensor.activity.DataActivity"
|
||||
android:exported="true" />
|
||||
|
134
app/src/main/assets/ic_device_supercars.svg
Normal file
134
app/src/main/assets/ic_device_supercars.svg
Normal file
@ -0,0 +1,134 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
width="28.740126"
|
||||
height="28.740126"
|
||||
viewBox="0 0 28.740126 28.740126"
|
||||
sodipodi:docname="ic_device_supercars.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata
|
||||
id="metadata8">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs6">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 14.370063 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="28.740126 : 14.370063 : 1"
|
||||
inkscape:persp3d-origin="14.370063 : 9.580042 : 1"
|
||||
id="perspective903" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1035"
|
||||
id="namedview4"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:zoom="11.313709"
|
||||
inkscape:cx="-18.826717"
|
||||
inkscape:cy="11.357902"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="45"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid972" />
|
||||
</sodipodi:namedview>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="Background"
|
||||
style="display:inline">
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="Bottom"
|
||||
style="display:inline"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="display:inline;fill:#1f7fdb;fill-opacity:1;stroke:none;stroke-width:3.57115;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect817-5"
|
||||
width="22.819572"
|
||||
height="21.904638"
|
||||
x="2.9239759"
|
||||
y="3.8768768"
|
||||
ry="0.9472276" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="Middle"
|
||||
style="display:inline"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="display:inline;fill:#4dabf5;fill-opacity:1;stroke:none;stroke-width:3.57115;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect817-7"
|
||||
width="22.819572"
|
||||
height="21.904638"
|
||||
x="2.9317887"
|
||||
y="3.0349438"
|
||||
ry="0.9472276" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Top"
|
||||
style="display:inline"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="fill:#2196f3;fill-opacity:1;stroke:none;stroke-width:3.57115;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect817"
|
||||
width="22.819572"
|
||||
height="21.904638"
|
||||
x="2.9238882"
|
||||
y="3.4130721"
|
||||
ry="0.9472276" />
|
||||
</g>
|
||||
<g
|
||||
id="g8"
|
||||
transform="matrix(0.75,0,0,0.75,5.3712747,5.3700628)"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.33333">
|
||||
<path
|
||||
d="M 21.96,11.22 C 21.57,7.01 17.76,4 13.56,4 13.37,4 13.18,4.01 12.99,4.02 2,4.74 2,17.2 2,17.2 V 18 c 0,1.1 0.9,2 2,2 h 10 c 4.67,0 8.41,-4.01 7.96,-8.78 z M 5.26,11.56 C 5.83,10.27 6.54,9.21 7.4,8.37 l 3.62,1.53 c 0.6,0.25 0.98,0.83 0.98,1.48 0,0.89 -0.72,1.61 -1.61,1.61 H 4.72 c 0.15,-0.46 0.32,-0.94 0.54,-1.43 z m 13.18,4.48 C 17.3,17.29 15.68,18 14,18 H 4 V 17.2 C 4,17.18 4.01,16.28 4.24,15 h 6.15 C 12.38,15 14,13.38 14,11.39 14,9.94 13.13,8.63 11.8,8.07 L 9.3,7.01 C 10.4,6.44 11.67,6.11 13.12,6.02 13.27,6 13.42,6 13.56,6 c 3.31,0 6.13,2.37 6.41,5.41 0.16,1.72 -0.38,3.36 -1.53,4.63 z"
|
||||
id="path6"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.33333" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer5"
|
||||
inkscape:label="Original"
|
||||
style="display:inline" />
|
||||
</svg>
|
After Width: | Height: | Size: 4.5 KiB |
179
app/src/main/assets/ic_device_supercars_disabled.svg
Normal file
179
app/src/main/assets/ic_device_supercars_disabled.svg
Normal file
@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
width="28.740126"
|
||||
height="28.740126"
|
||||
viewBox="0 0 28.740126 28.740126"
|
||||
sodipodi:docname="ic_device_supercars_disabled.svg"
|
||||
inkscape:version="1.2.1 (9c6d41e410, 2022-07-14)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<metadata
|
||||
id="metadata8">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs6">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 14.370063 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="28.740126 : 14.370063 : 1"
|
||||
inkscape:persp3d-origin="14.370063 : 9.580042 : 1"
|
||||
id="perspective903" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1035"
|
||||
id="namedview4"
|
||||
showgrid="false"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="0.125"
|
||||
inkscape:cy="7.65625"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="45"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="layer6"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:showpageshadow="2"
|
||||
inkscape:deskcolor="#d1d1d1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid972" />
|
||||
</sodipodi:namedview>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="Background"
|
||||
style="display:inline"
|
||||
sodipodi:insensitive="true">
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer4"
|
||||
inkscape:label="Bottom"
|
||||
style="display:inline"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="display:inline;fill:#7a7a7a;fill-opacity:1;stroke:none;stroke-width:3.57115;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect817-5"
|
||||
width="22.819572"
|
||||
height="21.904638"
|
||||
x="2.9239759"
|
||||
y="3.8768768"
|
||||
ry="0.9472276" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="Middle"
|
||||
style="display:inline"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="display:inline;fill:#9f9f9f;fill-opacity:0.941176;stroke:none;stroke-width:3.57115;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect817-7"
|
||||
width="22.819572"
|
||||
height="21.904638"
|
||||
x="2.9317887"
|
||||
y="3.0349438"
|
||||
ry="0.9472276" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="Top"
|
||||
style="display:inline"
|
||||
sodipodi:insensitive="true">
|
||||
<rect
|
||||
style="fill:#8a8a8a;fill-opacity:1;stroke:none;stroke-width:3.57115;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect817"
|
||||
width="22.819572"
|
||||
height="21.904638"
|
||||
x="2.9238882"
|
||||
y="3.4130721"
|
||||
ry="0.9472276" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer6"
|
||||
inkscape:label="Foreground"
|
||||
style="display:inline">
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer7"
|
||||
inkscape:label="Backplane"
|
||||
style="display:inline" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer8"
|
||||
inkscape:label="Frontplane"
|
||||
style="display:inline">
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer9"
|
||||
inkscape:label="Base"
|
||||
style="display:inline" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer10"
|
||||
inkscape:label="Top"
|
||||
style="display:inline" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer11"
|
||||
inkscape:label="Toptop"
|
||||
style="display:inline" />
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer12"
|
||||
inkscape:label="Toptoptop"
|
||||
style="display:inline" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#8a8a8a;fill-opacity:0.94117647"
|
||||
d="m 12.48275,10.865376 h 3.907 v 6.978 h -3.907 z"
|
||||
android:strokeWidth="1"
|
||||
id="path2735" />
|
||||
<g
|
||||
id="g8"
|
||||
transform="matrix(0.75,0,0,0.75,5.3712747,5.3700628)"
|
||||
style="display:inline;fill:#ffffff;fill-opacity:1;stroke-width:1.33333">
|
||||
<path
|
||||
d="M 21.96,11.22 C 21.57,7.01 17.76,4 13.56,4 13.37,4 13.18,4.01 12.99,4.02 2,4.74 2,17.2 2,17.2 V 18 c 0,1.1 0.9,2 2,2 h 10 c 4.67,0 8.41,-4.01 7.96,-8.78 z M 5.26,11.56 C 5.83,10.27 6.54,9.21 7.4,8.37 l 3.62,1.53 c 0.6,0.25 0.98,0.83 0.98,1.48 0,0.89 -0.72,1.61 -1.61,1.61 H 4.72 c 0.15,-0.46 0.32,-0.94 0.54,-1.43 z m 13.18,4.48 C 17.3,17.29 15.68,18 14,18 H 4 V 17.2 C 4,17.18 4.01,16.28 4.24,15 h 6.15 C 12.38,15 14,13.38 14,11.39 14,9.94 13.13,8.63 11.8,8.07 L 9.3,7.01 C 10.4,6.44 11.67,6.11 13.12,6.02 13.27,6 13.42,6 13.56,6 c 3.31,0 6.13,2.37 6.41,5.41 0.16,1.72 -0.38,3.36 -1.53,4.63 z"
|
||||
id="path6"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:1.33333" />
|
||||
</g>
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer5"
|
||||
inkscape:label="Original"
|
||||
style="display:inline" />
|
||||
</svg>
|
After Width: | Height: | Size: 5.7 KiB |
@ -0,0 +1,62 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.supercars;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.supercars.SuperCarsSupport;
|
||||
|
||||
public class ControlActivity extends AbstractGBActivity {
|
||||
LocalBroadcastManager localBroadcastManager;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_supercars_control);
|
||||
localBroadcastManager = LocalBroadcastManager.getInstance(this);
|
||||
|
||||
View.OnTouchListener controlTouchListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
String command = "idle";
|
||||
if (v.getId() == R.id.supercars_control_button_left_up) {
|
||||
command = "left_up";
|
||||
} else if (v.getId() == R.id.supercars_control_button_center_up) {
|
||||
command = "center_up";
|
||||
} else if (v.getId() == R.id.supercars_control_button_right_up) {
|
||||
command = "right_up";
|
||||
}
|
||||
if (v.getId() == R.id.supercars_control_button_left_down) {
|
||||
command = "left_down";
|
||||
} else if (v.getId() == R.id.supercars_control_button_center_down) {
|
||||
command = "center_down";
|
||||
} else if (v.getId() == R.id.supercars_control_button_right_down) {
|
||||
command = "right_down";
|
||||
}
|
||||
Intent intent = new Intent(SuperCarsSupport.COMMAND_DRIVE_CONTROL);
|
||||
intent.putExtra(SuperCarsSupport.EXTRA_DIRECTION, command);
|
||||
sendLocalBroadcast(intent);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
findViewById(R.id.supercars_control_button_left_up).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.supercars_control_button_center_up).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.supercars_control_button_right_up).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.supercars_control_button_left_down).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.supercars_control_button_center_down).setOnTouchListener(controlTouchListener);
|
||||
findViewById(R.id.supercars_control_button_right_down).setOnTouchListener(controlTouchListener);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void sendLocalBroadcast(Intent intent) {
|
||||
localBroadcastManager.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.supercars;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SuperCarsConstants {
|
||||
|
||||
public static final UUID SERVICE_UUID_FFF = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb");
|
||||
public static final UUID CHARACTERISTIC_UUID_FFF1 = UUID.fromString("d44bc439-abfd-45a2-b575-925416129600");
|
||||
public static final UUID CHARACTERISTIC_UUID_FFF2 = UUID.fromString("d44bc439-abfd-45a2-b575-92541612960a");
|
||||
public static final UUID CHARACTERISTIC_UUID_FFF3 = UUID.fromString("d44bc439-abfd-45a2-b575-92541612960b");
|
||||
public static final UUID CHARACTERISTIC_UUID_FFF4 = UUID.fromString("d44bc439-abfd-45a2-b575-925416129601");
|
||||
|
||||
public static final UUID SERVICE_UUID_FD = UUID.fromString("0000fd00-0000-1000-8000-00805f9b34fb");
|
||||
public static final UUID CHARACTERISTIC_UUID_FD1 = UUID.fromString("0000fd01-0000-1000-8000-00805f9b34fb");
|
||||
public static final UUID CHARACTERISTIC_UUID_FD2 = UUID.fromString("0000fd02-0000-1000-8000-00805f9b34fb");
|
||||
|
||||
public static final byte[] idle_data = new byte[]{0x02, 0x5e, 0x69, 0x5a, 0x48, (byte) 0xff, 0x2a, 0x43, (byte) 0x8c, (byte) 0xa6, (byte) 0x80, (byte) 0xf8, 0x3e, 0x04, (byte) 0xe4, 0x5d};
|
||||
public static final byte[] up_data = new byte[]{0x29, 0x60, (byte) 0x9c, 0x66, 0x48, 0x52, (byte) 0xcf, (byte) 0xf1, (byte) 0xb0, (byte) 0xf0, (byte) 0xcb, (byte) 0xb9, (byte) 0x80, 0x14, (byte) 0xbd, 0x2c};
|
||||
public static final byte[] down_data = new byte[]{0x03, 0x20, (byte) 0x99, 0x09, (byte) 0xba, (byte) 0x9d, (byte) 0xa1, (byte) 0xc8, (byte) 0xb9, (byte) 0x86, 0x16, 0x3c, 0x6d, 0x48, 0x46, 0x55};
|
||||
public static final byte[] left_data = new byte[]{0x51, 0x38, 0x21, 0x12, 0x13, 0x5c, (byte) 0xcc, (byte) 0xdb, (byte) 0x46, (byte) 0xcf, (byte) 0x89, 0x21, (byte) 0xb7, 0x05, 0x49, (byte) 0x9a};
|
||||
public static final byte[] right_data = new byte[]{0x1b, 0x57, 0x69, (byte) 0xcd, (byte) 0xf1, 0x3e, (byte) 0x8a, (byte) 0xb6, 0x27, 0x08, 0x0f, (byte) 0xf3, (byte) 0xce, (byte) 0xfc, 0x3b, (byte) 0xc0};
|
||||
|
||||
public static final byte[] up_left_data = new byte[]{(byte) 0x99, 0x28, (byte) 0xe5, (byte) 0x90, (byte) 0xdf, (byte) 0xe8, 0x21, 0x48, 0x5f, 0x41, 0x4f, (byte) 0xbb, 0x63, 0x3d, 0x5c, 0x4e};
|
||||
public static final byte[] up_right_data = new byte[]{0x0f, 0x2c, (byte) 0xe5, 0x66, 0x62, (byte) 0xd4, (byte) 0xfd, (byte) 0x9d, 0x32, (byte) 0xa4, 0x4f, 0x10, 0x2b, (byte) 0xf2, 0x0a, (byte) 0xa7};
|
||||
public static final byte[] down_left_data = new byte[]{(byte) 0x98, (byte) 0xce, (byte) 0x98, 0x1d, 0x58, (byte) 0xd1, 0x15, (byte) 0xaf, (byte) 0xe1, 0x19, 0x60, (byte) 0xbf, 0x46, 0x13, (byte) 0x92, 0x5c};
|
||||
public static final byte[] down_right_data = new byte[]{(byte) 0xf2, 0x52, 0x0f, (byte) 0xba, 0x31, 0x44, (byte) 0xfb, 0x11, 0x46, (byte) 0x8f, (byte) 0xe0, (byte) 0x80, (byte) 0xc6, (byte) 0xc2, (byte) 0xc2, 0x3c};
|
||||
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.supercars;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
|
||||
public class SuperCarsCoordinator extends AbstractDeviceCoordinator {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SuperCarsCoordinator.class);
|
||||
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||
try {
|
||||
BluetoothDevice device = candidate.getDevice();
|
||||
String name = device.getName();
|
||||
|
||||
if (name != null && name.startsWith("QCAR-")) {
|
||||
return DeviceType.SUPER_CARS;
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
LOG.error("unable to check device support", ex);
|
||||
}
|
||||
|
||||
return DeviceType.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceType getDeviceType() {
|
||||
return DeviceType.SUPER_CARS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBondingStyle() {
|
||||
return BONDING_STYLE_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatteryCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getAppsManagementActivity() {
|
||||
return ControlActivity.class;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<? extends Activity> getPairingActivity() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityDataFetching() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsActivityTracking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleProvider<? extends ActivitySample> getSampleProvider(GBDevice device, DaoSession session) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsScreenshots() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlarmSlotCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSmartWakeup(GBDevice device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturer() {
|
||||
return "Brand Base";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsAppsManagement() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsCalendarEvents() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsRealtimeData() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsFindDevice() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -118,6 +118,7 @@ public enum DeviceType {
|
||||
VESC_HM10(501, R.drawable.ic_device_vesc, R.drawable.ic_device_vesc_disabled, R.string.devicetype_vesc),
|
||||
BINARY_SENSOR(510, R.drawable.ic_device_unknown, R.drawable.ic_device_unknown_disabled, R.string.devicetype_binary_sensor),
|
||||
FLIPPER_ZERO(520, R.drawable.ic_device_flipper, R.drawable.ic_device_flipper_disabled, R.string.devicetype_flipper_zero),
|
||||
SUPER_CARS(530, R.drawable.ic_device_supercars, R.drawable.ic_device_supercars_disabled, R.string.devicetype_super_cars),
|
||||
TEST(1000, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_test);
|
||||
|
||||
private final int key;
|
||||
|
@ -99,6 +99,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.roidmi.RoidmiSupport
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.smaq2oss.SMAQ2OSSSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sony.headphones.SonyHeadphonesSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.sonyswr12.SonySWR12DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.supercars.SuperCarsSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.tlw64.TLW64Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.um25.Support.UM25Support;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.vesc.VescDeviceSupport;
|
||||
@ -333,6 +334,8 @@ public class DeviceSupportFactory {
|
||||
return new ServiceDeviceSupport(new BinarySensorSupport());
|
||||
case FLIPPER_ZERO:
|
||||
return new ServiceDeviceSupport(new FlipperZeroSupport());
|
||||
case SUPER_CARS:
|
||||
return new ServiceDeviceSupport(new SuperCarsSupport());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,261 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.supercars;
|
||||
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.Uri;
|
||||
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.supercars.SuperCarsConstants;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.fitpro.FitProDeviceSupport;
|
||||
|
||||
public class SuperCarsSupport extends AbstractBTLEDeviceSupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SuperCarsSupport.class);
|
||||
public static final String COMMAND_DRIVE_CONTROL = "nodomain.freeyourgadget.gadgetbridge.supercars.command.DRIVE_CONTROL";
|
||||
public static final String EXTRA_DIRECTION = "EXTRA_DIRECTION";
|
||||
|
||||
public SuperCarsSupport() {
|
||||
super(LOG);
|
||||
addSupportedService(SuperCarsConstants.SERVICE_UUID_FFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(COMMAND_DRIVE_CONTROL);
|
||||
broadcastManager.registerReceiver(commandReceiver, filter);
|
||||
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
|
||||
LOG.debug("name " + gbDevice.getName());
|
||||
return builder;
|
||||
}
|
||||
|
||||
BroadcastReceiver commandReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(COMMAND_DRIVE_CONTROL)) {
|
||||
SuperCarsSupport.this.setDirection(
|
||||
intent.getStringExtra(EXTRA_DIRECTION)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onNotification(NotificationSpec notificationSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteNotification(int id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetTime() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetCallState(CallSpec callSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetMusicState(MusicStateSpec stateSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetMusicInfo(MusicSpec musicSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnableRealtimeSteps(boolean enable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInstallApp(Uri uri) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppInfoReq() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppStart(UUID uuid, boolean start) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppDelete(UUID uuid) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppConfiguration(UUID appUuid, String config, Integer id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppReorder(UUID[] uuids) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFetchRecordedData(int dataTypes) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReset(int flags) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeartRateTest() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFindDevice(boolean start) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetConstantVibration(int integer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onScreenshotReq() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnableHeartRateSleepSupport(boolean enable) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetHeartRateMeasurementInterval(int seconds) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteCalendarEvent(byte type, long id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendConfiguration(String config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReadConfiguration(String config) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTestNewFunction() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendWeather(WeatherSpec weatherSpec) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAutoConnect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setDirection(String direction) {
|
||||
byte[] command = SuperCarsConstants.idle_data;
|
||||
|
||||
switch (direction) {
|
||||
case "left_up":
|
||||
command = SuperCarsConstants.up_left_data;
|
||||
break;
|
||||
case "center_up":
|
||||
command = SuperCarsConstants.up_data;
|
||||
break;
|
||||
case "right_up":
|
||||
command = SuperCarsConstants.up_right_data;
|
||||
break;
|
||||
case "left_down":
|
||||
command = SuperCarsConstants.down_left_data;
|
||||
break;
|
||||
case "center_down":
|
||||
command = SuperCarsConstants.down_data;
|
||||
break;
|
||||
case "right_down":
|
||||
command = SuperCarsConstants.down_right_data;
|
||||
break;
|
||||
default:
|
||||
command = SuperCarsConstants.idle_data;
|
||||
}
|
||||
TransactionBuilder builder = new TransactionBuilder("test");
|
||||
BluetoothGattCharacteristic writeCharacteristic = getCharacteristic(SuperCarsConstants.CHARACTERISTIC_UUID_FFF1);
|
||||
builder.write(writeCharacteristic, command);
|
||||
builder.queue(getQueue());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
super.dispose();
|
||||
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(commandReceiver);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.supercars.SuperCarsCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.fitpro.FitProDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.banglejs.BangleJSCoordinator;
|
||||
@ -341,6 +342,7 @@ public class DeviceHelper {
|
||||
result.add(new QC35Coordinator());
|
||||
result.add(new BinarySensorCoordinator());
|
||||
result.add(new FlipperZeroCoordinator());
|
||||
result.add(new SuperCarsCoordinator());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
22
app/src/main/res/drawable/ic_device_supercars.xml
Normal file
22
app/src/main/res/drawable/ic_device_supercars.xml
Normal file
@ -0,0 +1,22 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="45sp"
|
||||
android:height="45sp"
|
||||
android:viewportWidth="30"
|
||||
android:viewportHeight="30">
|
||||
<path
|
||||
android:fillColor="#1f7fdb"
|
||||
android:pathData="M3.871 3.877h20.925a0.947 0.947 0 0 1 0.948 0.947v20.01a0.947 0.947 0 0 1-0.948 0.948H3.871a0.947 0.947 0 0 1-0.947-0.948V4.824a0.947 0.947 0 0 1 0.947-0.947z"
|
||||
android:strokeWidth="3.57115" />
|
||||
<path
|
||||
android:fillColor="#4dabf5"
|
||||
android:pathData="M3.879 3.035h20.925a0.947 0.947 0 0 1 0.947 0.947v20.01a0.947 0.947 0 0 1-0.947 0.948H3.88a0.947 0.947 0 0 1-0.947-0.948V3.982A0.947 0.947 0 0 1 3.88 3.035z"
|
||||
android:strokeWidth="3.57115" />
|
||||
<path
|
||||
android:fillColor="#2196f3"
|
||||
android:pathData="M3.871 3.413h20.925a0.947 0.947 0 0 1 0.948 0.947v20.01a0.947 0.947 0 0 1-0.948 0.948H3.871a0.947 0.947 0 0 1-0.947-0.948V4.36A0.947 0.947 0 0 1 3.87 3.413z"
|
||||
android:strokeWidth="3.57115" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M21.841 13.785c-0.292-3.157-3.15-5.415-6.3-5.415-0.142 0-0.285 0.008-0.427 0.015C6.87 8.925 6.87 18.27 6.87 18.27v0.6c0 0.825 0.675 1.5 1.5 1.5h7.5c3.503 0 6.308-3.007 5.97-6.585zM9.316 14.04c0.428-0.967 0.96-1.762 1.605-2.392l2.715 1.147c0.45 0.188 0.735 0.623 0.735 1.11 0 0.668-0.54 1.208-1.207 1.208H8.91c0.113-0.345 0.24-0.705 0.405-1.073zm9.885 3.36c-0.855 0.938-2.07 1.47-3.33 1.47h-7.5v-0.6c0-0.015 0.008-0.69 0.18-1.65h4.613c1.492 0 2.707-1.215 2.707-2.707 0-1.088-0.652-2.07-1.65-2.49l-1.875-0.795c0.825-0.428 1.778-0.675 2.865-0.743 0.113-0.015 0.225-0.015 0.33-0.015 2.483 0 4.598 1.778 4.808 4.058 0.12 1.29-0.285 2.52-1.148 3.472z"
|
||||
android:strokeWidth="0.9999975" />
|
||||
</vector>
|
27
app/src/main/res/drawable/ic_device_supercars_disabled.xml
Normal file
27
app/src/main/res/drawable/ic_device_supercars_disabled.xml
Normal file
@ -0,0 +1,27 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="45sp"
|
||||
android:height="45sp"
|
||||
android:viewportWidth="30"
|
||||
android:viewportHeight="30">
|
||||
<path
|
||||
android:fillColor="#7a7a7a"
|
||||
android:pathData="M3.871 3.877h20.925a0.947 0.947 0 0 1 0.948 0.947v20.01a0.947 0.947 0 0 1-0.948 0.948H3.871a0.947 0.947 0 0 1-0.947-0.948V4.824a0.947 0.947 0 0 1 0.947-0.947z"
|
||||
android:strokeWidth="3.57115" />
|
||||
<path
|
||||
android:fillAlpha="0.941176"
|
||||
android:fillColor="#9f9f9f"
|
||||
android:pathData="M3.879 3.035h20.925a0.947 0.947 0 0 1 0.947 0.947v20.01a0.947 0.947 0 0 1-0.947 0.948H3.88a0.947 0.947 0 0 1-0.947-0.948V3.982A0.947 0.947 0 0 1 3.88 3.035z"
|
||||
android:strokeWidth="3.57115" />
|
||||
<path
|
||||
android:fillColor="#8a8a8a"
|
||||
android:pathData="M3.871 3.413h20.925a0.947 0.947 0 0 1 0.948 0.947v20.01a0.947 0.947 0 0 1-0.948 0.948H3.871a0.947 0.947 0 0 1-0.947-0.948V4.36A0.947 0.947 0 0 1 3.87 3.413z"
|
||||
android:strokeWidth="3.57115" />
|
||||
<path
|
||||
android:fillAlpha="0.9411765"
|
||||
android:fillColor="#8a8a8a"
|
||||
android:pathData="M12.483 10.865h3.907v6.978h-3.907z" />
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="M21.841 13.785c-0.292-3.157-3.15-5.415-6.3-5.415-0.142 0-0.285 0.008-0.427 0.015C6.87 8.925 6.87 18.27 6.87 18.27v0.6c0 0.825 0.675 1.5 1.5 1.5h7.5c3.503 0 6.308-3.007 5.97-6.585zM9.316 14.04c0.428-0.967 0.96-1.762 1.605-2.392l2.715 1.147c0.45 0.188 0.735 0.623 0.735 1.11 0 0.668-0.54 1.208-1.207 1.208H8.91c0.113-0.345 0.24-0.705 0.405-1.073zm9.885 3.36c-0.855 0.938-2.07 1.47-3.33 1.47h-7.5v-0.6c0-0.015 0.008-0.69 0.18-1.65h4.613c1.492 0 2.707-1.215 2.707-2.707 0-1.088-0.652-2.07-1.65-2.49l-1.875-0.795c0.825-0.428 1.778-0.675 2.865-0.743 0.113-0.015 0.225-0.015 0.33-0.015 2.483 0 4.598 1.778 4.808 4.058 0.12 1.29-0.285 2.52-1.148 3.472z"
|
||||
android:strokeWidth="0.9999975" />
|
||||
</vector>
|
74
app/src/main/res/layout/activity_supercars_control.xml
Normal file
74
app/src/main/res/layout/activity_supercars_control.xml
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/supercars_control_button_left_up"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="left" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/supercars_control_button_center_up"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="forward" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/supercars_control_button_right_up"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="right" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/supercars_control_button_left_down"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="left" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/supercars_control_button_center_down"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="back" />
|
||||
|
||||
|
||||
<Button
|
||||
android:id="@+id/supercars_control_button_right_down"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="100dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="right" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -1843,6 +1843,7 @@
|
||||
<string name="prefs_hourly_chime">Hourly chime</string>
|
||||
<string name="prefs_hourly_chime_summary">The watch will beep once an hour</string>
|
||||
<string name="devicetype_flipper_zero">Flipper zero</string>
|
||||
<string name="devicetype_super_cars">Shell Racing</string>
|
||||
<string name="activity_prefs_allow_bluetooth_intent_api">Bluetooth Intent API</string>
|
||||
<string name="activity_prefs_summary_allow_bluetooth_intent_api">Allow controlling Bluetooth connection via Intent API</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user