mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-02-13 18:55:29 +01:00
Gree Air Conditioner: Initial support
This commit is contained in:
parent
feb5134b5d
commit
7b2b162d55
1
.idea/dictionaries/t.xml
generated
1
.idea/dictionaries/t.xml
generated
@ -53,6 +53,7 @@
|
||||
<w>gideão</w>
|
||||
<w>girolamo</w>
|
||||
<w>gobbetti</w>
|
||||
<w>gree</w>
|
||||
<w>greenberg</w>
|
||||
<w>greenrobot</w>
|
||||
<w>greffier</w>
|
||||
|
1
app/proguard-rules.pro
vendored
1
app/proguard-rules.pro
vendored
@ -72,6 +72,7 @@
|
||||
-keepclassmembers,allowobfuscation class * {
|
||||
@com.google.gson.annotations.SerializedName <fields>;
|
||||
}
|
||||
-keep class nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages.** {*; }
|
||||
# Somehow the rule above was not enough for some
|
||||
-keep class nodomain.freeyourgadget.gadgetbridge.devices.pinetime.InfiniTimeDFU* { *; }
|
||||
|
||||
|
@ -647,6 +647,10 @@
|
||||
android:name=".devices.evenrealities.G1PairingActivity"
|
||||
android:label="@string/title_activity_even_realities_g1_pairing"
|
||||
android:parentActivityName=".activities.discovery.DiscoveryActivityV2" />
|
||||
<activity
|
||||
android:name=".devices.gree.GreeAcPairingActivity"
|
||||
android:label="@string/devicetype_gree_ac"
|
||||
android:parentActivityName=".activities.discovery.DiscoveryActivityV2" />
|
||||
<activity
|
||||
android:name=".devices.watch9.Watch9PairingActivity"
|
||||
android:label="@string/title_activity_watch9_pairing" />
|
||||
|
124
app/src/main/assets/ic_device_air_conditioning.svg
Normal file
124
app/src/main/assets/ic_device_air_conditioning.svg
Normal file
@ -0,0 +1,124 @@
|
||||
<?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_galaxy_buds.svg"
|
||||
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
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" /><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="22.627418"
|
||||
inkscape:cx="8.1096305"
|
||||
inkscape:cy="10.982252"
|
||||
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"
|
||||
originx="0"
|
||||
originy="0"
|
||||
spacingy="1"
|
||||
spacingx="1"
|
||||
units="px" /><inkscape:page
|
||||
x="0"
|
||||
y="0"
|
||||
width="28.740126"
|
||||
height="28.740126"
|
||||
id="page2"
|
||||
margin="0"
|
||||
bleed="0" /></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="g2507"
|
||||
transform="matrix(0.99999822,0,0,1,0.29668164,-0.00953878)"><g
|
||||
style="fill:#ffffff"
|
||||
id="g1"
|
||||
transform="matrix(0.01921905,0,0,0.01921902,4.4167806,4.9004638)"><path
|
||||
d="m 383.2,941.6 c -4,0 -6.4,-0.8 -9.6,-2.4 -14.4,-9.6 -82.4,-60 -25.6,-160 15.2,-27.2 19.2,-48.8 13.6,-66.4 -6.4,-20 -27.2,-28 -27.2,-28 -9.6,-4 -14.4,-15.2 -10.4,-24.8 3.2,-8 9.6,-12.8 17.6,-12.8 2.4,0 4.8,0.8 7.2,1.6 3.2,0 36.8,14.4 50.4,50.4 10.4,28.8 4.8,62.4 -16.8,100 -40,70.4 2.4,101.6 11.2,107.2 8.8,4.8 12,16.8 7.2,26.4 -4.8,6.4 -12,8.8 -17.6,8.8 z m 129.6,-42.4 c -4,0 -6.4,-0.8 -9.6,-2.4 -28.8,-16.8 -69.6,-68.8 -24,-150.4 13.6,-24.8 17.6,-44.8 12,-60 -5.6,-17.6 -24,-24.8 -24,-24.8 -10.4,-4 -15.2,-14.4 -11.2,-24.8 3.2,-8 9.6,-12.8 17.6,-12.8 2.4,0 4.8,0.8 7.2,1.6 8,3.2 36,16 47.2,48 9.6,27.2 4.8,58.4 -15.2,92.8 -38.4,68.8 8,96.8 10.4,97.6 4,2.4 7.2,6.4 8.8,11.2 1.6,4.8 0.8,10.4 -1.6,15.2 -4.8,6.4 -12,8.8 -17.6,8.8 z m -265.6,0 c -4,0 -6.4,-0.8 -9.6,-2.4 C 208.8,880 168,828 213.6,746.4 c 13.6,-24.8 17.6,-44.8 12,-60 -5.6,-17.6 -24,-24.8 -24,-24.8 -10.4,-4 -15.2,-14.4 -11.2,-24.8 3.2,-8 9.6,-12.8 17.6,-12.8 2.4,0 4.8,0.8 7.2,1.6 8,3.2 36,16.8 47.2,48 9.6,27.2 4,58.4 -15.2,93.6 -38.4,68.8 8,96.8 10.4,97.6 4,2.4 7.2,6.4 8.8,11.2 1.6,4.8 0.8,10.4 -1.6,15.2 -4,5.6 -12,8 -17.6,8 z M 734.4,828 c -6.4,0 -11.2,-2.4 -15.2,-6.4 -4,-4 -6.4,-9.6 -6.4,-15.2 0,-8.8 5.6,-16.8 13.6,-20.8 h 0.8 v -43.2 l -40.8,23.2 v 0.8 c 0,6.4 -2.4,14.4 -10.4,18.4 -3.2,2.4 -7.2,3.2 -11.2,3.2 -8,0 -15.2,-4 -18.4,-10.4 -3.2,-5.6 -4,-11.2 -2.4,-16.8 1.6,-5.6 4.8,-10.4 10.4,-12.8 3.2,-2.4 7.2,-3.2 10.4,-3.2 4,0 8,0.8 11.2,3.2 l 36.8,-20.8 -36,-20.8 c -4.8,1.6 -8.8,2.4 -12,2.4 -4,0 -7.2,-0.8 -10.4,-2.4 -9.6,-6.4 -13.6,-20 -8,-29.6 4,-6.4 11.2,-10.4 19.2,-10.4 4,0 8,0.8 11.2,3.2 6.4,4 10.4,10.4 10.4,18.4 v 0.8 L 728,712 v -43.2 h -0.8 c -8,-4 -13.6,-12 -13.6,-20.8 0,-12 9.6,-21.6 21.6,-21.6 6.4,0 12,2.4 16,6.4 4,4 6.4,9.6 6.4,15.2 0,7.2 -4,14.4 -11.2,18.4 H 744 V 708 l 35.2,-20 v -0.8 c 0,-6.4 2.4,-14.4 10.4,-18.4 3.2,-2.4 7.2,-3.2 11.2,-3.2 8,0 15.2,4 18.4,10.4 3.2,5.6 4,11.2 2.4,16.8 -1.6,5.6 -4.8,10.4 -10.4,12.8 -3.2,2.4 -7.2,3.2 -10.4,3.2 -4,0 -8,-0.8 -11.2,-3.2 l -36.8,20.8 36,20.8 c 4.8,-1.6 8.8,-2.4 12,-2.4 4,0 7.2,0.8 10.4,2.4 9.6,6.4 13.6,20 8,29.6 -4,6.4 -11.2,10.4 -19.2,10.4 -4,0 -8,-0.8 -11.2,-3.2 -6.4,-4 -10.4,-10.4 -10.4,-18.4 v -0.8 L 744,745.6 v 41.6 h 0.8 c 7.2,3.2 11.2,10.4 11.2,18.4 0,12.8 -9.6,22.4 -21.6,22.4 z M 152,575.2 C 91.2,575.2 42.4,526.4 42.4,465.6 V 204.8 C 42.4,144 91.2,95.2 152,95.2 h 721.6 c 60.8,0 109.6,48.8 109.6,109.6 v 260.8 c 0,60.8 -48.8,109.6 -109.6,109.6 z m -11.2,-432 c -28.8,0 -52,24 -52,54.4 V 476 c 0,29.6 23.2,54.4 52,54.4 H 884 c 28.8,0 52,-24 52,-54.4 V 197.6 c 0,-29.6 -23.2,-54.4 -52,-54.4 z m 21.6,312 c -10.4,0 -19.2,-8.8 -19.2,-19.2 0,-10.4 8.8,-19.2 19.2,-19.2 h 682.4 c 10.4,0 19.2,8.8 19.2,19.2 0,10.4 -8.8,19.2 -19.2,19.2 z m 0,-80.8 c -10.4,0 -19.2,-8.8 -19.2,-19.2 0,-10.4 8.8,-19.2 19.2,-19.2 h 682.4 c 10.4,0 19.2,8.8 19.2,19.2 0,10.4 -8.8,19.2 -19.2,19.2 z"
|
||||
fill=""
|
||||
id="path1"
|
||||
style="fill:#ffffff" /></g></g></g><g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer5"
|
||||
inkscape:label="Original"
|
||||
style="display:none"
|
||||
sodipodi:insensitive="true"><image
|
||||
y="0.0079936879"
|
||||
x="0.010951031"
|
||||
id="image4124"
|
||||
xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAMAAADVRocKAAAAA3NCSVQICAjb4U/gAAAACXBIWXMA ADFOAAAxTgGacD5yAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAAABF0RVh0 VGl0bGUAUGViYmxlIEljb26KvwD9AAAADHRFWHRBdXRob3IAeHBobnh/4OzMAAAAY3RFWHRDb3B5 cmlnaHQAQ0MgQXR0cmlidXRpb24tTm9uQ29tbWVyY2lhbC1TaGFyZUFsaWtlIGh0dHA6Ly9jcmVh dGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5jLXNhLzMuMC/eBBrlAAABy1BMVEUAAAAAAAAA AP8AAIAAAFUAAKoAVaoAAIAAQIAAM2YAM5kzM2YzM5krK4AkJG0kJJIgIIAcHHEcHI4aGoAXF3QX F4sXLnQXLosVK4AUJ3YUJ4kSJIAkJIARInciInciIogQIIAgIIAeHngeHoccHIAcK4AbKHkbKIYa GoAaJoAYJHkXI4AXI4sWIXoWIYUVIIAfH3ofH4UdJ4ATHIQcJnsbJIAaI4QaIoAZIXsZIYQYIHgY IIAXH4MXJ3wXHoAXJoBLpfAWJHwdJHwdJIMcI4Acas0VIoMbIoAaIXwaIIAZH3wZH4MZJXwYHoAY HoYYJIAehtsYHoIefdtHoO0jetZGovNEn+4gg+EfgN5Ep/VKqfREpvQgfdkgfttKqvQggd4hjesw nPMwnPRJqfUhgd4hjutJqfUgfttNq/VNq/QhlPEhlPIhlvMkmPMglvIff9sgjeoglPAhk/AhlPEh lPIhlvMkl/MkmPMlmPMmmPMnmfMpmvMzn/Q0n/Q1n/Q2oPRIqfVNq/VasfZbsvZhtPZitfdtuveQ yvmXzvmj0/qk1Pqu2fu83/vR6f3T6v3Z7f3i8f3j8v3l8/7m8/7p9f7q9f7x+P7y+f7////ougeB AAAAb3RSTlMAAQECAwMDBAQFBQUFBgcHCAkJCgsLCwsMDQ0ODg8PDxAQERESEhMTFBQVFhYXFxgZ GRobGxwdHh8fICAhISIiIiMjIyQkJSYnKCkpKSoqKiorKyssLC2xs7O0tba2tu7u7u7u7+/w8fHy +/v7+/ywJhX9AAAC0klEQVRo3u2a+VfTQBCAm00iW0nSTVNKbKQYbIMUC6jU4q2IB2rF+74vPEAR LSjIIXgAAiqef65py6MNJe17y1RF8/26L/N1N9O8ZGZcLof/DiYFoiV1cZHwiGVZjh7zalRAYYbn sFsQ6RFwGccyBeJjwSMrPn8lHX6fQqRy3tbAsFiU1So9FA4bNIRD63XNTwTO5pSYc9fuvwbgwaW9 SxqYs/eGBgcAGBy+fRrlpRPDsJdfJoEYuMgvzibz/vK3kmDcFMuxNZvM/BG74QTdFV6PJZsYlhe9 XXCCrlCVStwcyhG45QCkoCmiV0o4uwXEib4aQMHjbc0RTXYvCMx/mGdNHaSgraWxRhEXzsgUEC0C KWjfszlUYRWsrYcUHGttNlSRzxUEo5CCjrZYrSqVVlD3Nwj6vqcZsovzKrPeTy3o/5lmxE4wnFl/ 4QhKLvjy2YY5IEExHMH0B1umQQSj9o+EUUewIBh/m8c4qOBbfu58dQRLCmYnJmZLKphKJicdwR8X vJsymSmhIM37FSv4OJlhxnlUOAJHAC8Ye5PHmPNe9PsEJX/5dT5AigvmPtkw53wnr3xB34809uWc zDp9OWflV7xgBaBlzY79MWORALhuui+vbhoArfwe3rUp5MtWfl2Il1QDUtAaj+rKakv1XdEhBfGm Wo1kq+/pM1Ih+wdRI6iIq3IFvEAewgke6QHFg1mU26PjhbtwghsKEbG1X8ew3PmnUPGfXRAwv7hr yqAD13t6nwPQ23PnBMeivG4gg85c7XwCQOeVU+avZ5bslcrrNm7dfehIInGSguOJo+0Hd27ZoOam j3ULvOjTI02x+PYddLTEY42GJpfnpo/L0g50k8pqI1IfbWikoSFaXxfSFKnMrqFsZpKbKKoWDFbT EdQCqlfCdhtIG7AoESLTQogk4EJd/VRTn8fLgecKTg3MjyUsA4SKDD7MT1bQ8++NmvwCRmydh2Fg UvEAAAAASUVORK5CYII= "
|
||||
style="opacity:0.490741;image-rendering:optimizeQuality"
|
||||
preserveAspectRatio="none"
|
||||
height="28.710279"
|
||||
width="28.710279" /></g></svg>
|
After Width: | Height: | Size: 9.1 KiB |
@ -0,0 +1,72 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.gree;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.gree.GreeAcSupport;
|
||||
|
||||
public class GreeAcCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull final GBDevice gbDevice, @NonNull final Device device, @NonNull final DaoSession session) throws GBException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pattern getSupportedDeviceName() {
|
||||
// GR-AC_10001_09_xxxx_SC
|
||||
return Pattern.compile("^GR-AC_\\d{5}_\\d{2}_[0-9a-f]{4}_SC$");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturer() {
|
||||
return "Gree";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<? extends DeviceSupport> getDeviceSupportClass() {
|
||||
return GreeAcSupport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBondingStyle() {
|
||||
return BONDING_STYLE_NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceNameResource() {
|
||||
return R.string.devicetype_gree_ac;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDefaultIconResource() {
|
||||
return R.drawable.ic_device_air_conditioning;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDisabledIconResource() {
|
||||
return R.drawable.ic_device_air_conditioning_disabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean suggestUnbindBeforePair() {
|
||||
// shouldn't matter
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Class<? extends Activity> getPairingActivity() {
|
||||
return GreeAcPairingActivity.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,265 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.gree;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.gree.GreeAcPrefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
|
||||
|
||||
public class GreeAcPairingActivity extends AbstractGBActivity {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GreeAcPairingActivity.class);
|
||||
|
||||
public static final String ACTION_BIND_STATUS = "nodomain.freeyourgadget.gadgetbridge.gree.bind_status";
|
||||
public static final String EXTRA_BIND_KEY = "extra_bind_key";
|
||||
public static final String EXTRA_BIND_MESSAGE = "extra_bind_message";
|
||||
|
||||
private GBDeviceCandidate deviceCandidate;
|
||||
|
||||
private TextInputLayout textLayoutSsid;
|
||||
private TextInputLayout textLayoutPassword;
|
||||
private TextInputLayout textLayoutHost;
|
||||
private TextInputEditText editTextSsid;
|
||||
private TextInputEditText editTextPassword;
|
||||
private TextInputEditText editTextHost;
|
||||
private ProgressBar progressBar;
|
||||
private TextView pairResultTextView;
|
||||
private Button buttonPair;
|
||||
private Button buttonCopy;
|
||||
|
||||
private GBDevice gbDevice;
|
||||
private String bindKey;
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ACTION_BIND_STATUS.equals(action)) {
|
||||
final String bindMessage = intent.getStringExtra(EXTRA_BIND_MESSAGE);
|
||||
bindKey = intent.getStringExtra(EXTRA_BIND_KEY);
|
||||
|
||||
progressBar.setVisibility(View.GONE);
|
||||
if ("1".equals(bindMessage)) {
|
||||
pairResultTextView.setText(getString(R.string.gree_pair_status_success, String.valueOf(bindKey)));
|
||||
buttonCopy.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
pairResultTextView.setText(getString(R.string.gree_pair_status_failure, bindMessage));
|
||||
}
|
||||
|
||||
pairResultTextView.setVisibility(View.VISIBLE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GBDevice.ACTION_DEVICE_CHANGED.equals(action)) {
|
||||
final GBDevice actionDevice = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
if (actionDevice == null || !actionDevice.getAddress().equals(deviceCandidate.getMacAddress())) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG.debug("Got device state: {}", actionDevice.getState());
|
||||
|
||||
if (actionDevice.getState() == GBDevice.State.NOT_CONNECTED && buttonCopy.getVisibility() != View.VISIBLE) {
|
||||
pairResultTextView.setText(getString(R.string.gree_pair_status_failure, actionDevice.getState().toString()));
|
||||
pairResultTextView.setVisibility(View.VISIBLE);
|
||||
|
||||
editTextSsid.setEnabled(true);
|
||||
editTextPassword.setEnabled(true);
|
||||
editTextHost.setEnabled(true);
|
||||
buttonPair.setVisibility(View.VISIBLE);
|
||||
progressBar.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
LOG.error("Unknown action {}", action);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
deviceCandidate = intent.getParcelableExtra(DeviceCoordinator.EXTRA_DEVICE_CANDIDATE);
|
||||
|
||||
if (deviceCandidate == null) {
|
||||
GB.toast(this, "Device candidate missing", Toast.LENGTH_LONG, GB.ERROR);
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
setContentView(R.layout.activity_gree_ac_pairing);
|
||||
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(ACTION_BIND_STATUS);
|
||||
filter.addAction(GBDevice.ACTION_DEVICE_CHANGED);
|
||||
ContextCompat.registerReceiver(this, mReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED);
|
||||
|
||||
final TextView textPairInfo = findViewById(R.id.gree_pair_info);
|
||||
textLayoutSsid = findViewById(R.id.gree_pair_ssid_layout);
|
||||
textLayoutPassword = findViewById(R.id.gree_pair_password_layout);
|
||||
textLayoutHost = findViewById(R.id.gree_pair_host_layout);
|
||||
editTextSsid = findViewById(R.id.gree_pair_ssid_text);
|
||||
editTextPassword = findViewById(R.id.gree_pair_password_text);
|
||||
editTextHost = findViewById(R.id.gree_pair_host_text);
|
||||
progressBar = findViewById(R.id.gree_pair_progress_bar);
|
||||
pairResultTextView = findViewById(R.id.gree_pair_result);
|
||||
buttonPair = findViewById(R.id.gree_button_pair);
|
||||
buttonCopy = findViewById(R.id.gree_button_copy);
|
||||
|
||||
textPairInfo.setText(getString(R.string.gree_pair_info, deviceCandidate.getName(), deviceCandidate.getMacAddress()));
|
||||
|
||||
final DevicePrefs devicePrefs = new DevicePrefs(GBApplication.getDeviceSpecificSharedPrefs(deviceCandidate.getMacAddress()), gbDevice);
|
||||
editTextSsid.setText(devicePrefs.getString(GreeAcPrefs.PREF_SSID, ""));
|
||||
editTextPassword.setText(devicePrefs.getString(GreeAcPrefs.PREF_PASSWORD, ""));
|
||||
editTextHost.setText(devicePrefs.getString(GreeAcPrefs.PREF_HOST, ""));
|
||||
|
||||
editTextSsid.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
textLayoutSsid.setError(null);
|
||||
}
|
||||
});
|
||||
editTextPassword.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
textLayoutPassword.setError(null);
|
||||
}
|
||||
});
|
||||
editTextHost.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
textLayoutHost.setError(null);
|
||||
}
|
||||
});
|
||||
|
||||
buttonPair.setOnClickListener(v -> {
|
||||
savePrefs();
|
||||
|
||||
final String ssid = editTextSsid.getText() != null ? editTextSsid.getText().toString() : "";
|
||||
if (ssid.isEmpty() || ssid.length() > 32) {
|
||||
textLayoutSsid.setError("Invalid SSID");
|
||||
return;
|
||||
}
|
||||
final String password = editTextPassword.getText() != null ? editTextPassword.getText().toString() : "";
|
||||
if (password.isEmpty() || password.length() < 8 || password.length() > 63) {
|
||||
textLayoutPassword.setError("Invalid password");
|
||||
return;
|
||||
}
|
||||
final String host = editTextHost.getText() != null ? editTextHost.getText().toString() : "";
|
||||
if (host.isEmpty()) {
|
||||
textLayoutHost.setError("Invalid host");
|
||||
return;
|
||||
}
|
||||
|
||||
editTextSsid.setEnabled(false);
|
||||
editTextPassword.setEnabled(false);
|
||||
editTextHost.setEnabled(false);
|
||||
buttonPair.setVisibility(View.GONE);
|
||||
progressBar.setVisibility(View.VISIBLE);
|
||||
pairResultTextView.setVisibility(View.GONE);
|
||||
|
||||
GBApplication.deviceService().disconnect();
|
||||
gbDevice = DeviceHelper.getInstance().toSupportedDevice(deviceCandidate.getDevice());
|
||||
GBApplication.deviceService(gbDevice).connect(true);
|
||||
});
|
||||
|
||||
buttonCopy.setOnClickListener(v -> {
|
||||
final ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
final String clipboardData = getString(
|
||||
R.string.gree_pair_clipboard,
|
||||
deviceCandidate.getName(),
|
||||
deviceCandidate.getMacAddress(),
|
||||
bindKey
|
||||
);
|
||||
final ClipData clip = ClipData.newPlainText(deviceCandidate.getName(), clipboardData);
|
||||
clipboard.setPrimaryClip(clip);
|
||||
GB.toast(getString(R.string.copied_to_clipboard), Toast.LENGTH_LONG, GB.INFO);
|
||||
});
|
||||
|
||||
final ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
actionBar.setTitle(deviceCandidate.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (gbDevice != null) {
|
||||
GBApplication.deviceService(gbDevice).disconnect();
|
||||
}
|
||||
unregisterReceiver(mReceiver);
|
||||
}
|
||||
|
||||
private void savePrefs() {
|
||||
final DevicePrefs devicePrefs = new DevicePrefs(GBApplication.getDeviceSpecificSharedPrefs(deviceCandidate.getMacAddress()), gbDevice);
|
||||
final SharedPreferences.Editor editor = devicePrefs.getPreferences().edit();
|
||||
if (editTextSsid != null && editTextSsid.getText() != null) {
|
||||
editor.putString(GreeAcPrefs.PREF_SSID, editTextSsid.getText().toString());
|
||||
}
|
||||
if (editTextPassword != null && editTextPassword.getText() != null) {
|
||||
editor.putString(GreeAcPrefs.PREF_PASSWORD, editTextPassword.getText().toString());
|
||||
}
|
||||
if (editTextHost != null && editTextHost.getText() != null) {
|
||||
editor.putString(GreeAcPrefs.PREF_HOST, editTextHost.getText().toString());
|
||||
}
|
||||
editor.apply();
|
||||
}
|
||||
}
|
@ -120,6 +120,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.vivomove.Garm
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.vivomove.GarminVivomoveTrendCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.vivosmart.GarminVivosmart5Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.vivosport.GarminVivosportCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.gree.GreeAcCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.hama.fit6900.HamaFit6900DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.EXRIZUK8Coordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.hplus.HPlusCoordinator;
|
||||
@ -514,6 +515,7 @@ public enum DeviceType {
|
||||
GARMIN_VIVOACTIVE_5(GarminVivoActive5Coordinator.class),
|
||||
GARMIN_VIVOSMART_5(GarminVivosmart5Coordinator.class),
|
||||
GARMIN_VIVOSPORT(GarminVivosportCoordinator.class),
|
||||
GREE_AC(GreeAcCoordinator.class),
|
||||
VIBRATISSIMO(VibratissimoCoordinator.class),
|
||||
SONY_SWR12(SonySWR12DeviceCoordinator.class),
|
||||
LIVEVIEW(LiveviewCoordinator.class),
|
||||
|
@ -0,0 +1,7 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree;
|
||||
|
||||
public class GreeAcPrefs {
|
||||
public static final String PREF_SSID = "gree_ssid";
|
||||
public static final String PREF_PASSWORD = "gree_password";
|
||||
public static final String PREF_HOST = "gree_host";
|
||||
}
|
@ -0,0 +1,231 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.content.Intent;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Locale;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.gree.GreeAcPairingActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
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.gree.messages.AbstractGreeMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages.GreeBindMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages.GreeBleInfoMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages.GreeBleKeyMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages.GreePackMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages.GreeWlanMessage;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.CryptoUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
|
||||
|
||||
public class GreeAcSupport extends AbstractBTLEDeviceSupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(GreeAcSupport.class);
|
||||
|
||||
public static final UUID UUID_SERVICE_GREE_PACK = UUID.fromString("0000fd06-173c-93d2-488e-fe144d2e12a2");
|
||||
public static final UUID UUID_CHARACTERISTIC_PACK_TX = UUID.fromString("0000fd03-0000-1000-8000-00805f9b34fb");
|
||||
public static final UUID UUID_CHARACTERISTIC_PACK_RX = UUID.fromString("0000fd04-0000-1000-8000-00805f9b34fb");
|
||||
|
||||
public static final byte[] DEFAULT_KEY = "a3K8Bx%2r8Y7#xDh".getBytes();
|
||||
|
||||
private byte[] bindKey = null;
|
||||
|
||||
private BluetoothGattCharacteristic characteristicTx;
|
||||
|
||||
public GreeAcSupport() {
|
||||
super(LOG);
|
||||
addSupportedService(UUID_SERVICE_GREE_PACK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAutoConnect() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransactionBuilder initializeDevice(final TransactionBuilder builder) {
|
||||
characteristicTx = getCharacteristic(UUID_CHARACTERISTIC_PACK_TX);
|
||||
final BluetoothGattCharacteristic characteristicRx = getCharacteristic(UUID_CHARACTERISTIC_PACK_RX);
|
||||
|
||||
if (characteristicTx == null || characteristicRx == null) {
|
||||
LOG.warn("Pack characteristics are null");
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.NOT_CONNECTED, getContext()));
|
||||
return builder;
|
||||
}
|
||||
|
||||
characteristicTx.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
|
||||
|
||||
builder.notify(getCharacteristic(UUID_CHARACTERISTIC_PACK_RX), true);
|
||||
|
||||
final String mac = getDevice().getAddress().trim().replace(":", "").toLowerCase(Locale.ROOT);
|
||||
writeMessage(builder, new GreeBindMessage(mac.substring(mac.length() - 4)));
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
|
||||
if (super.onCharacteristicChanged(gatt, characteristic)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final UUID characteristicUUID = characteristic.getUuid();
|
||||
final byte[] value = characteristic.getValue();
|
||||
|
||||
if (UUID_CHARACTERISTIC_PACK_RX.equals(characteristicUUID)) {
|
||||
final String packMessageJson = new String(value, StandardCharsets.UTF_8);
|
||||
LOG.debug("Got pack: {}", packMessageJson);
|
||||
|
||||
final AbstractGreeMessage message;
|
||||
try {
|
||||
message = AbstractGreeMessage.fromJson(packMessageJson);
|
||||
} catch (final Exception e) {
|
||||
LOG.error("Failed to deserialize message from json", e);
|
||||
return true;
|
||||
}
|
||||
|
||||
handleMessage(message);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG.warn("Unknown characteristic {} changed: {}", characteristicUUID, GB.hexdump(value));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleMessage(final AbstractGreeMessage message) {
|
||||
if (message instanceof GreePackMessage) {
|
||||
final GreePackMessage packMessage = (GreePackMessage) message;
|
||||
final int encryptionKeyNum = packMessage.getEncryptionKey();
|
||||
|
||||
final byte[] key;
|
||||
switch (encryptionKeyNum) {
|
||||
case GreePackMessage.KEY_BIND:
|
||||
key = bindKey;
|
||||
break;
|
||||
case GreePackMessage.KEY_DEFAULT:
|
||||
key = DEFAULT_KEY;
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unknown pack message encryption key {}", encryptionKeyNum);
|
||||
return;
|
||||
}
|
||||
|
||||
if (key == null) {
|
||||
LOG.error("Key {} is not known", encryptionKeyNum);
|
||||
return;
|
||||
}
|
||||
|
||||
final byte[] encryptedBytes = Base64.decode(packMessage.getPack(), Base64.DEFAULT);
|
||||
final byte[] decryptedBytes;
|
||||
try {
|
||||
decryptedBytes = CryptoUtils.decryptAES_ECB_Pad(encryptedBytes, key);
|
||||
} catch (final GeneralSecurityException e) {
|
||||
LOG.error("Failed to decrypt pack", e);
|
||||
return;
|
||||
}
|
||||
|
||||
final AbstractGreeMessage packSubMessage;
|
||||
try {
|
||||
final String subMessageJson = new String(decryptedBytes, StandardCharsets.UTF_8);
|
||||
LOG.debug("Pack sub message: {}", subMessageJson);
|
||||
|
||||
packSubMessage = AbstractGreeMessage.fromJson(subMessageJson);
|
||||
} catch (final Exception e) {
|
||||
LOG.error("Failed to deserialize pack sub message from json", e);
|
||||
return;
|
||||
}
|
||||
|
||||
handleMessage(packSubMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message instanceof GreeBleKeyMessage) {
|
||||
final GreeBleKeyMessage bleKeyMessage = (GreeBleKeyMessage) message;
|
||||
|
||||
LOG.debug("Got bind key: {}", bleKeyMessage.getKey());
|
||||
bindKey = bleKeyMessage.getKey().getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences("authkey", bleKeyMessage.getKey()));
|
||||
|
||||
final DevicePrefs devicePrefs = getDevicePrefs();
|
||||
final String host = devicePrefs.getString(GreeAcPrefs.PREF_HOST, "");
|
||||
final String psw = devicePrefs.getString(GreeAcPrefs.PREF_PASSWORD, "");
|
||||
final String ssid = devicePrefs.getString(GreeAcPrefs.PREF_SSID, "");
|
||||
if (host.isEmpty() || psw.isEmpty() || ssid.isEmpty()) {
|
||||
final Intent intent = new Intent(GreeAcPairingActivity.ACTION_BIND_STATUS);
|
||||
intent.setPackage(BuildConfig.APPLICATION_ID);
|
||||
intent.putExtra(GreeAcPairingActivity.EXTRA_BIND_MESSAGE, "missing wlan params");
|
||||
getContext().sendBroadcast(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
final TransactionBuilder builder = createTransactionBuilder("setup wifi");
|
||||
writeMessage(builder, new GreeWlanMessage(host, psw, ssid, 1));
|
||||
builder.queue(getQueue());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (message instanceof GreeBleInfoMessage) {
|
||||
final GreeBleInfoMessage bleInfoMessage = (GreeBleInfoMessage) message;
|
||||
|
||||
LOG.debug("Got ble info, wificon = {}", bleInfoMessage.getWificon());
|
||||
|
||||
final Intent intent = new Intent(GreeAcPairingActivity.ACTION_BIND_STATUS);
|
||||
intent.setPackage(BuildConfig.APPLICATION_ID);
|
||||
intent.putExtra(GreeAcPairingActivity.EXTRA_BIND_KEY, new String(bindKey));
|
||||
intent.putExtra(GreeAcPairingActivity.EXTRA_BIND_MESSAGE, String.valueOf(bleInfoMessage.getWificon()));
|
||||
getContext().sendBroadcast(intent);
|
||||
|
||||
// TODO disconnect - not much else we can do
|
||||
}
|
||||
|
||||
LOG.warn("Unhandled message: {}", message);
|
||||
}
|
||||
|
||||
private void writeMessage(final TransactionBuilder builder, final AbstractGreeMessage message) {
|
||||
final String messageJson = message.toString();
|
||||
|
||||
LOG.debug("Will send: {}", messageJson);
|
||||
|
||||
if (message instanceof GreePackMessage) {
|
||||
builder.write(characteristicTx, messageJson.getBytes(StandardCharsets.UTF_8));
|
||||
return;
|
||||
}
|
||||
|
||||
final int key;
|
||||
final byte[] encryptedBytes;
|
||||
try {
|
||||
if (message instanceof GreeBindMessage) {
|
||||
key = GreePackMessage.KEY_DEFAULT;
|
||||
encryptedBytes = CryptoUtils.encryptAES_ECB_Pad(messageJson.getBytes(StandardCharsets.UTF_8), DEFAULT_KEY);
|
||||
} else {
|
||||
if (bindKey == null) {
|
||||
LOG.error("No bind key, unable to encrypt");
|
||||
return;
|
||||
}
|
||||
key = GreePackMessage.KEY_BIND;
|
||||
encryptedBytes = CryptoUtils.encryptAES_ECB_Pad(messageJson.getBytes(StandardCharsets.UTF_8), bindKey);
|
||||
}
|
||||
} catch (final GeneralSecurityException e) {
|
||||
LOG.error("Failed to encrypt message", e);
|
||||
return;
|
||||
}
|
||||
|
||||
final GreePackMessage packMessage = new GreePackMessage(Base64.encodeToString(encryptedBytes, Base64.DEFAULT).replace("\n", "").trim(), key);
|
||||
writeMessage(builder, packMessage);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.typeadapters.RuntimeTypeAdapterFactory;
|
||||
|
||||
public abstract class AbstractGreeMessage {
|
||||
private static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeAdapterFactory(getTypeAdapterFactory())
|
||||
.serializeNulls()
|
||||
.disableHtmlEscaping()
|
||||
.create();
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return GSON.toJson(this);
|
||||
}
|
||||
|
||||
public static TypeAdapterFactory getTypeAdapterFactory() {
|
||||
return RuntimeTypeAdapterFactory
|
||||
.of(AbstractGreeMessage.class, "t")
|
||||
.registerSubtype(GreePackMessage.class, GreePackMessage.TYPE)
|
||||
.registerSubtype(GreeBindMessage.class, GreeBindMessage.TYPE)
|
||||
.registerSubtype(GreeBleInfoMessage.class, GreeBleInfoMessage.TYPE)
|
||||
.registerSubtype(GreeBleKeyMessage.class, GreeBleKeyMessage.TYPE)
|
||||
.registerSubtype(GreeWlanMessage.class, GreeWlanMessage.TYPE)
|
||||
.recognizeSubtypes();
|
||||
}
|
||||
|
||||
public static AbstractGreeMessage fromJson(final String json) {
|
||||
return GSON.fromJson(json, AbstractGreeMessage.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages;
|
||||
|
||||
public class GreeBindMessage extends AbstractGreeMessage {
|
||||
public static final String TYPE = "bind";
|
||||
|
||||
private final String mac;
|
||||
private final int IsCP;
|
||||
|
||||
public GreeBindMessage(final String mac) {
|
||||
this.mac = mac;
|
||||
this.IsCP = 1;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages;
|
||||
|
||||
public class GreeBleInfoMessage extends AbstractGreeMessage {
|
||||
public static final String TYPE = "bleinfo";
|
||||
|
||||
private final int wificon;
|
||||
private final String mac;
|
||||
private final String mid;
|
||||
private final String ver;
|
||||
|
||||
public GreeBleInfoMessage(final int wificon, final String mac, final String mid, final String ver) {
|
||||
this.wificon = wificon;
|
||||
this.mac = mac;
|
||||
this.mid = mid;
|
||||
this.ver = ver;
|
||||
}
|
||||
|
||||
public int getWificon() {
|
||||
return wificon;
|
||||
}
|
||||
|
||||
public String getMac() {
|
||||
return mac;
|
||||
}
|
||||
|
||||
public String getMid() {
|
||||
return mid;
|
||||
}
|
||||
|
||||
public String getVer() {
|
||||
return ver;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages;
|
||||
|
||||
public class GreeBleKeyMessage extends AbstractGreeMessage {
|
||||
public static final String TYPE = "blekey";
|
||||
|
||||
private final String key;
|
||||
|
||||
public GreeBleKeyMessage(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages;
|
||||
|
||||
public class GreePackMessage extends AbstractGreeMessage {
|
||||
public static final String TYPE = "pack";
|
||||
|
||||
public static final int KEY_DEFAULT = 1;
|
||||
public static final int KEY_BIND = 0;
|
||||
|
||||
private final String pack;
|
||||
private final int i;
|
||||
private final int pIn;
|
||||
|
||||
public GreePackMessage(final String pack, final int encryptionKey) {
|
||||
this.pack = pack;
|
||||
this.i = encryptionKey;
|
||||
this.pIn = 0;
|
||||
}
|
||||
|
||||
public String getPack() {
|
||||
return pack;
|
||||
}
|
||||
|
||||
public int getEncryptionKey() {
|
||||
return i;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.gree.messages;
|
||||
|
||||
public class GreeWlanMessage extends AbstractGreeMessage {
|
||||
public static final String TYPE = "wlan";
|
||||
|
||||
private final String host;
|
||||
private final String psw;
|
||||
private final String ssid;
|
||||
private final int num;
|
||||
|
||||
public GreeWlanMessage(final String host, final String psw, final String ssid, final int num) {
|
||||
this.host = host;
|
||||
this.psw = psw;
|
||||
this.ssid = ssid;
|
||||
this.num = num;
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ import android.annotation.SuppressLint;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
@ -71,6 +72,20 @@ public class CryptoUtils {
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
public static byte[] encryptAES_ECB_Pad(byte[] data, byte[] key) throws GeneralSecurityException {
|
||||
final Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
final SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
public static byte[] decryptAES_ECB_Pad(byte[] data, byte[] key) throws GeneralSecurityException {
|
||||
final Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
|
||||
final SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
|
||||
return cipher.doFinal(data);
|
||||
}
|
||||
|
||||
public static byte[] encryptAES_GCM_NoPad(byte[] data, byte[] key, byte[] iv, byte[] aad) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
||||
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
||||
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
|
||||
|
33
app/src/main/res/drawable/ic_device_air_conditioning.xml
Normal file
33
app/src/main/res/drawable/ic_device_air_conditioning.xml
Normal file
@ -0,0 +1,33 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="28.7dp"
|
||||
android:height="28.7dp"
|
||||
android:viewportWidth="28.74"
|
||||
android:viewportHeight="28.74">
|
||||
|
||||
<!--
|
||||
Adapted from https://www.svgrepo.com/svg/493976/air-conditioner
|
||||
-->
|
||||
|
||||
<path
|
||||
android:fillColor="?attr/deviceIconLight"
|
||||
android:pathData="M3.871,3.877L24.796,3.877A0.947,0.947 0,0 1,25.744 4.824L25.744,24.834A0.947,0.947 0,0 1,24.796 25.782L3.871,25.782A0.947,0.947 0,0 1,2.924 24.834L2.924,4.824A0.947,0.947 0,0 1,3.871 3.877z"
|
||||
android:strokeWidth="3.57115"
|
||||
android:strokeColor="#00000000" />
|
||||
|
||||
<path
|
||||
android:fillColor="?attr/deviceIconDark"
|
||||
android:pathData="M3.879,3.035L24.804,3.035A0.947,0.947 0,0 1,25.751 3.982L25.751,23.992A0.947,0.947 0,0 1,24.804 24.94L3.879,24.94A0.947,0.947 0,0 1,2.932 23.992L2.932,3.982A0.947,0.947 0,0 1,3.879 3.035z"
|
||||
android:strokeWidth="3.57115"
|
||||
android:strokeColor="#00000000" />
|
||||
|
||||
<path
|
||||
android:fillColor="?attr/deviceIconPrimary"
|
||||
android:pathData="M3.871,3.413L24.796,3.413A0.947,0.947 0,0 1,25.743 4.36L25.743,24.37A0.947,0.947 0,0 1,24.796 25.318L3.871,25.318A0.947,0.947 0,0 1,2.924 24.37L2.924,4.36A0.947,0.947 0,0 1,3.871 3.413z"
|
||||
android:strokeWidth="3.57115"
|
||||
android:strokeColor="#00000000" />
|
||||
|
||||
<path
|
||||
android:fillColor="?attr/deviceIconOnPrimary"
|
||||
android:pathData="m12.078,22.988c-0.077,0 -0.123,-0.015 -0.185,-0.046 -0.277,-0.185 -1.584,-1.153 -0.492,-3.075 0.292,-0.523 0.369,-0.938 0.261,-1.276 -0.123,-0.384 -0.523,-0.538 -0.523,-0.538 -0.185,-0.077 -0.277,-0.292 -0.2,-0.477 0.062,-0.154 0.185,-0.246 0.338,-0.246 0.046,0 0.092,0.015 0.138,0.031 0.062,0 0.707,0.277 0.969,0.969 0.2,0.554 0.092,1.199 -0.323,1.922 -0.769,1.353 0.046,1.953 0.215,2.06 0.169,0.092 0.231,0.323 0.138,0.507 -0.092,0.123 -0.231,0.169 -0.338,0.169zM14.569,22.173c-0.077,0 -0.123,-0.015 -0.185,-0.046 -0.554,-0.323 -1.338,-1.322 -0.461,-2.891 0.261,-0.477 0.338,-0.861 0.231,-1.153 -0.108,-0.338 -0.461,-0.477 -0.461,-0.477 -0.2,-0.077 -0.292,-0.277 -0.215,-0.477 0.062,-0.154 0.185,-0.246 0.338,-0.246 0.046,0 0.092,0.015 0.138,0.031 0.154,0.062 0.692,0.308 0.907,0.923 0.185,0.523 0.092,1.122 -0.292,1.784 -0.738,1.322 0.154,1.86 0.2,1.876 0.077,0.046 0.138,0.123 0.169,0.215 0.031,0.092 0.015,0.2 -0.031,0.292 -0.092,0.123 -0.231,0.169 -0.338,0.169zM9.464,22.173c-0.077,0 -0.123,-0.015 -0.185,-0.046C8.726,21.804 7.942,20.804 8.819,19.236c0.261,-0.477 0.338,-0.861 0.231,-1.153 -0.108,-0.338 -0.461,-0.477 -0.461,-0.477 -0.2,-0.077 -0.292,-0.277 -0.215,-0.477 0.062,-0.154 0.185,-0.246 0.338,-0.246 0.046,0 0.092,0.015 0.138,0.031 0.154,0.062 0.692,0.323 0.907,0.923 0.185,0.523 0.077,1.122 -0.292,1.799 -0.738,1.322 0.154,1.86 0.2,1.876 0.077,0.046 0.138,0.123 0.169,0.215 0.031,0.092 0.015,0.2 -0.031,0.292 -0.077,0.108 -0.231,0.154 -0.338,0.154zM18.828,20.804c-0.123,0 -0.215,-0.046 -0.292,-0.123 -0.077,-0.077 -0.123,-0.185 -0.123,-0.292 0,-0.169 0.108,-0.323 0.261,-0.4l0.015,0l0,-0.83l-0.784,0.446l0,0.015c0,0.123 -0.046,0.277 -0.2,0.354 -0.062,0.046 -0.138,0.062 -0.215,0.062 -0.154,0 -0.292,-0.077 -0.354,-0.2 -0.062,-0.108 -0.077,-0.215 -0.046,-0.323 0.031,-0.108 0.092,-0.2 0.2,-0.246 0.062,-0.046 0.138,-0.062 0.2,-0.062 0.077,0 0.154,0.015 0.215,0.062l0.707,-0.4 -0.692,-0.4c-0.092,0.031 -0.169,0.046 -0.231,0.046 -0.077,0 -0.138,-0.015 -0.2,-0.046 -0.185,-0.123 -0.261,-0.384 -0.154,-0.569 0.077,-0.123 0.215,-0.2 0.369,-0.2 0.077,0 0.154,0.015 0.215,0.062 0.123,0.077 0.2,0.2 0.2,0.354l0,0.015L18.705,18.575l0,-0.83l-0.015,0c-0.154,-0.077 -0.261,-0.231 -0.261,-0.4 0,-0.231 0.185,-0.415 0.415,-0.415 0.123,0 0.231,0.046 0.308,0.123 0.077,0.077 0.123,0.185 0.123,0.292 0,0.138 -0.077,0.277 -0.215,0.354L19.012,17.698L19.012,18.498l0.677,-0.384l0,-0.015c0,-0.123 0.046,-0.277 0.2,-0.354 0.062,-0.046 0.138,-0.062 0.215,-0.062 0.154,0 0.292,0.077 0.354,0.2 0.062,0.108 0.077,0.215 0.046,0.323 -0.031,0.108 -0.092,0.2 -0.2,0.246 -0.062,0.046 -0.138,0.062 -0.2,0.062 -0.077,0 -0.154,-0.015 -0.215,-0.062l-0.707,0.4 0.692,0.4c0.092,-0.031 0.169,-0.046 0.231,-0.046 0.077,0 0.138,0.015 0.2,0.046 0.185,0.123 0.261,0.384 0.154,0.569 -0.077,0.123 -0.215,0.2 -0.369,0.2 -0.077,0 -0.154,-0.015 -0.215,-0.062 -0.123,-0.077 -0.2,-0.2 -0.2,-0.354l0,-0.015L19.012,19.221l0,0.8l0.015,0c0.138,0.062 0.215,0.2 0.215,0.354 0,0.246 -0.185,0.431 -0.415,0.431zM7.635,15.946C6.466,15.946 5.528,15.008 5.528,13.839L5.528,8.827C5.528,7.658 6.466,6.721 7.635,6.721l13.868,0c1.169,0 2.106,0.938 2.106,2.106l0,5.012c0,1.169 -0.938,2.106 -2.106,2.106zM7.419,7.643c-0.554,0 -0.999,0.461 -0.999,1.046L6.42,14.039c0,0.569 0.446,1.046 0.999,1.046L21.703,15.085c0.554,0 0.999,-0.461 0.999,-1.046L22.702,8.689c0,-0.569 -0.446,-1.046 -0.999,-1.046zM7.835,13.639c-0.2,0 -0.369,-0.169 -0.369,-0.369 0,-0.2 0.169,-0.369 0.369,-0.369l13.115,0c0.2,0 0.369,0.169 0.369,0.369 0,0.2 -0.169,0.369 -0.369,0.369zM7.835,12.087c-0.2,0 -0.369,-0.169 -0.369,-0.369 0,-0.2 0.169,-0.369 0.369,-0.369l13.115,0c0.2,0 0.369,0.169 0.369,0.369 0,0.2 -0.169,0.369 -0.369,0.369z" />
|
||||
|
||||
</vector>
|
@ -0,0 +1,33 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="28.7dp"
|
||||
android:height="28.7dp"
|
||||
android:viewportWidth="28.74"
|
||||
android:viewportHeight="28.74">
|
||||
|
||||
<!--
|
||||
Adapted from https://www.svgrepo.com/svg/493976/air-conditioner
|
||||
-->
|
||||
|
||||
<path
|
||||
android:fillColor="#7a7a7a"
|
||||
android:pathData="M3.871,3.877L24.796,3.877A0.947,0.947 0,0 1,25.744 4.824L25.744,24.834A0.947,0.947 0,0 1,24.796 25.782L3.871,25.782A0.947,0.947 0,0 1,2.924 24.834L2.924,4.824A0.947,0.947 0,0 1,3.871 3.877z"
|
||||
android:strokeWidth="3.57115"
|
||||
android:strokeColor="#00000000" />
|
||||
|
||||
<path
|
||||
android:fillColor="#9f9f9f"
|
||||
android:pathData="M3.879,3.035L24.804,3.035A0.947,0.947 0,0 1,25.751 3.982L25.751,23.992A0.947,0.947 0,0 1,24.804 24.94L3.879,24.94A0.947,0.947 0,0 1,2.932 23.992L2.932,3.982A0.947,0.947 0,0 1,3.879 3.035z"
|
||||
android:strokeWidth="3.57115"
|
||||
android:strokeColor="#00000000" />
|
||||
|
||||
<path
|
||||
android:fillColor="#8a8a8a"
|
||||
android:pathData="M3.871,3.413L24.796,3.413A0.947,0.947 0,0 1,25.743 4.36L25.743,24.37A0.947,0.947 0,0 1,24.796 25.318L3.871,25.318A0.947,0.947 0,0 1,2.924 24.37L2.924,4.36A0.947,0.947 0,0 1,3.871 3.413z"
|
||||
android:strokeWidth="3.57115"
|
||||
android:strokeColor="#00000000" />
|
||||
|
||||
<path
|
||||
android:fillColor="#ffffff"
|
||||
android:pathData="m12.078,22.988c-0.077,0 -0.123,-0.015 -0.185,-0.046 -0.277,-0.185 -1.584,-1.153 -0.492,-3.075 0.292,-0.523 0.369,-0.938 0.261,-1.276 -0.123,-0.384 -0.523,-0.538 -0.523,-0.538 -0.185,-0.077 -0.277,-0.292 -0.2,-0.477 0.062,-0.154 0.185,-0.246 0.338,-0.246 0.046,0 0.092,0.015 0.138,0.031 0.062,0 0.707,0.277 0.969,0.969 0.2,0.554 0.092,1.199 -0.323,1.922 -0.769,1.353 0.046,1.953 0.215,2.06 0.169,0.092 0.231,0.323 0.138,0.507 -0.092,0.123 -0.231,0.169 -0.338,0.169zM14.569,22.173c-0.077,0 -0.123,-0.015 -0.185,-0.046 -0.554,-0.323 -1.338,-1.322 -0.461,-2.891 0.261,-0.477 0.338,-0.861 0.231,-1.153 -0.108,-0.338 -0.461,-0.477 -0.461,-0.477 -0.2,-0.077 -0.292,-0.277 -0.215,-0.477 0.062,-0.154 0.185,-0.246 0.338,-0.246 0.046,0 0.092,0.015 0.138,0.031 0.154,0.062 0.692,0.308 0.907,0.923 0.185,0.523 0.092,1.122 -0.292,1.784 -0.738,1.322 0.154,1.86 0.2,1.876 0.077,0.046 0.138,0.123 0.169,0.215 0.031,0.092 0.015,0.2 -0.031,0.292 -0.092,0.123 -0.231,0.169 -0.338,0.169zM9.464,22.173c-0.077,0 -0.123,-0.015 -0.185,-0.046C8.726,21.804 7.942,20.804 8.819,19.236c0.261,-0.477 0.338,-0.861 0.231,-1.153 -0.108,-0.338 -0.461,-0.477 -0.461,-0.477 -0.2,-0.077 -0.292,-0.277 -0.215,-0.477 0.062,-0.154 0.185,-0.246 0.338,-0.246 0.046,0 0.092,0.015 0.138,0.031 0.154,0.062 0.692,0.323 0.907,0.923 0.185,0.523 0.077,1.122 -0.292,1.799 -0.738,1.322 0.154,1.86 0.2,1.876 0.077,0.046 0.138,0.123 0.169,0.215 0.031,0.092 0.015,0.2 -0.031,0.292 -0.077,0.108 -0.231,0.154 -0.338,0.154zM18.828,20.804c-0.123,0 -0.215,-0.046 -0.292,-0.123 -0.077,-0.077 -0.123,-0.185 -0.123,-0.292 0,-0.169 0.108,-0.323 0.261,-0.4l0.015,0l0,-0.83l-0.784,0.446l0,0.015c0,0.123 -0.046,0.277 -0.2,0.354 -0.062,0.046 -0.138,0.062 -0.215,0.062 -0.154,0 -0.292,-0.077 -0.354,-0.2 -0.062,-0.108 -0.077,-0.215 -0.046,-0.323 0.031,-0.108 0.092,-0.2 0.2,-0.246 0.062,-0.046 0.138,-0.062 0.2,-0.062 0.077,0 0.154,0.015 0.215,0.062l0.707,-0.4 -0.692,-0.4c-0.092,0.031 -0.169,0.046 -0.231,0.046 -0.077,0 -0.138,-0.015 -0.2,-0.046 -0.185,-0.123 -0.261,-0.384 -0.154,-0.569 0.077,-0.123 0.215,-0.2 0.369,-0.2 0.077,0 0.154,0.015 0.215,0.062 0.123,0.077 0.2,0.2 0.2,0.354l0,0.015L18.705,18.575l0,-0.83l-0.015,0c-0.154,-0.077 -0.261,-0.231 -0.261,-0.4 0,-0.231 0.185,-0.415 0.415,-0.415 0.123,0 0.231,0.046 0.308,0.123 0.077,0.077 0.123,0.185 0.123,0.292 0,0.138 -0.077,0.277 -0.215,0.354L19.012,17.698L19.012,18.498l0.677,-0.384l0,-0.015c0,-0.123 0.046,-0.277 0.2,-0.354 0.062,-0.046 0.138,-0.062 0.215,-0.062 0.154,0 0.292,0.077 0.354,0.2 0.062,0.108 0.077,0.215 0.046,0.323 -0.031,0.108 -0.092,0.2 -0.2,0.246 -0.062,0.046 -0.138,0.062 -0.2,0.062 -0.077,0 -0.154,-0.015 -0.215,-0.062l-0.707,0.4 0.692,0.4c0.092,-0.031 0.169,-0.046 0.231,-0.046 0.077,0 0.138,0.015 0.2,0.046 0.185,0.123 0.261,0.384 0.154,0.569 -0.077,0.123 -0.215,0.2 -0.369,0.2 -0.077,0 -0.154,-0.015 -0.215,-0.062 -0.123,-0.077 -0.2,-0.2 -0.2,-0.354l0,-0.015L19.012,19.221l0,0.8l0.015,0c0.138,0.062 0.215,0.2 0.215,0.354 0,0.246 -0.185,0.431 -0.415,0.431zM7.635,15.946C6.466,15.946 5.528,15.008 5.528,13.839L5.528,8.827C5.528,7.658 6.466,6.721 7.635,6.721l13.868,0c1.169,0 2.106,0.938 2.106,2.106l0,5.012c0,1.169 -0.938,2.106 -2.106,2.106zM7.419,7.643c-0.554,0 -0.999,0.461 -0.999,1.046L6.42,14.039c0,0.569 0.446,1.046 0.999,1.046L21.703,15.085c0.554,0 0.999,-0.461 0.999,-1.046L22.702,8.689c0,-0.569 -0.446,-1.046 -0.999,-1.046zM7.835,13.639c-0.2,0 -0.369,-0.169 -0.369,-0.369 0,-0.2 0.169,-0.369 0.369,-0.369l13.115,0c0.2,0 0.369,0.169 0.369,0.369 0,0.2 -0.169,0.369 -0.369,0.369zM7.835,12.087c-0.2,0 -0.369,-0.169 -0.369,-0.369 0,-0.2 0.169,-0.369 0.369,-0.369l13.115,0c0.2,0 0.369,0.169 0.369,0.369 0,0.2 -0.169,0.369 -0.369,0.369z" />
|
||||
|
||||
</vector>
|
125
app/src/main/res/layout/activity_gree_ac_pairing.xml
Normal file
125
app/src/main/res/layout/activity_gree_ac_pairing.xml
Normal file
@ -0,0 +1,125 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.discovery.DiscoveryActivityV2">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/gree_scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/about_margin"
|
||||
android:paddingRight="@dimen/about_margin"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.OpenFwAppInstallerActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gree_pair_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:text="@string/gree_pair_info"
|
||||
android:textIsSelectable="true" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/gree_pair_ssid_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/gree_pair_ssid_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:hint="@string/wifi_ssid"
|
||||
android:inputType="textFilter|textNoSuggestions"
|
||||
android:maxLength="32"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/gree_pair_password_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/gree_pair_password_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:autofillHints="wifiPassword"
|
||||
android:hint="@string/prefs_password"
|
||||
android:inputType="textPassword"
|
||||
android:maxLength="63"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/gree_pair_host_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/gree_pair_host_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:hint="@string/gree_controller_host"
|
||||
android:inputType="textFilter|textNoSuggestions"
|
||||
android:singleLine="true" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/gree_button_pair"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
android:text="@string/discovery_yes_pair" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/gree_pair_progress_bar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="0dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gree_pair_result"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/stats_empty_value"
|
||||
android:textIsSelectable="true"
|
||||
android:visibility="gone" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/gree_button_copy"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:text="@string/copy_to_clipboard"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
</LinearLayout>
|
@ -1358,6 +1358,7 @@
|
||||
<string name="discovery_successfully_bonded">Bound to %1$s.</string>
|
||||
<string name="discovery_pair_title">Pair with %1$s?</string>
|
||||
<string name="discovery_pair_question">Select Pair to pair your devices. If this fails, try again without pairing.</string>
|
||||
<string name="copy_to_clipboard">Copy</string>
|
||||
<string name="discovery_yes_pair">Pair</string>
|
||||
<string name="discovery_dont_pair">Don\'t Pair</string>
|
||||
<!-- strings sent to pebble watches for quick actions -->
|
||||
@ -1814,6 +1815,7 @@
|
||||
<string name="devicetype_garmin_vivoactive_5">Garmin Vívoactive 5</string>
|
||||
<string name="devicetype_garmin_vivosmart_5">Garmin Vívosmart 5</string>
|
||||
<string name="devicetype_garmin_vivosport">Garmin Vívosport</string>
|
||||
<string name="devicetype_gree_ac">Gree Air Conditioner</string>
|
||||
<string name="devicetype_vibratissimo">Vibratissimo</string>
|
||||
<string name="devicetype_um25">UM-25</string>
|
||||
<string name="devicetype_liveview">LiveView</string>
|
||||
@ -3631,4 +3633,9 @@
|
||||
<string name="pref_garmin_fake_oauth_warning">Do not enable this if you plan to use the official app or connect the watch to the internet. After enabling this setting, you may need to factory reset the watch to authenticate again.</string>
|
||||
<string name="pref_garmin_fake_oauth_title">Send fake OAuth responses</string>
|
||||
<string name="pref_garmin_fake_oauth_summary">Fixes some functions such as weather and AGPS updates without connecting to the official app every 90 days.</string>
|
||||
<string name="gree_controller_host">Host</string>
|
||||
<string name="gree_pair_info">You are about to pair with %s (%s). Please enter the Wi-Fi and host server information for pairing. See the website for more information.</string>
|
||||
<string name="gree_pair_status_success">Pairing success.\n\nBind key: %s</string>
|
||||
<string name="gree_pair_status_failure">Pairing failed: %s</string>
|
||||
<string name="gree_pair_clipboard">Device name: %s\nMac address: %s\nBind key: %s</string>
|
||||
</resources>
|
||||
|
Loading…
x
Reference in New Issue
Block a user