mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
AAWireless: Experimental support
This commit is contained in:
Generated
+1
@@ -1,6 +1,7 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="t">
|
||||
<words>
|
||||
<w>aawireless</w>
|
||||
<w>abettenburg</w>
|
||||
<w>adhikary</w>
|
||||
<w>afanasev</w>
|
||||
|
||||
+6
@@ -325,6 +325,12 @@ public class DeviceSettingsPreferenceConst {
|
||||
public static final String WIFI_HOTSPOT_STOP = "wifi_hotspot_stop";
|
||||
public static final String WIFI_HOTSPOT_STATUS = "wifi_hotspot_status";
|
||||
|
||||
public static final String PREF_WIFI_FREQUENCY = "wifi_frequency";
|
||||
public static final String PREF_WIFI_CHANNEL_2_4 = "wifi_channel_2_4";
|
||||
public static final String PREF_WIFI_CHANNEL_5 = "wifi_channel_5";
|
||||
|
||||
public static final String PREF_COUNTRY = "country";
|
||||
|
||||
public static final String PREF_APP_LOGS_START = "pref_app_logs_start";
|
||||
public static final String PREF_APP_LOGS_STOP = "pref_app_logs_stop";
|
||||
public static final String PREF_DEVICE_LOGS_TOGGLE = "device_logs_enabled";
|
||||
|
||||
+40
@@ -16,6 +16,7 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.devicesettings;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.text.Spanned;
|
||||
@@ -24,6 +25,9 @@ import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.MultiSelectListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -241,4 +245,40 @@ public final class DeviceSettingsUtils {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void addConfirmablePreferenceHandlerFor(final DeviceSpecificSettingsHandler handler,
|
||||
final String preferenceKey,
|
||||
final int alertMessage) {
|
||||
final Preference pref = handler.findPreference(preferenceKey);
|
||||
if (pref == null) {
|
||||
return;
|
||||
}
|
||||
pref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
final Context context = handler.getContext();
|
||||
final CharSequence preferenceName = pref.getTitle();
|
||||
final String title = context.getString(R.string.earfun_change_confirm_title, preferenceName);
|
||||
final String message = context.getString(alertMessage);
|
||||
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(handler.getContext().getString(R.string.ok), (dialog, which) -> {
|
||||
if (pref instanceof EditTextPreference) {
|
||||
((EditTextPreference) pref).setText(newValue.toString());
|
||||
} else if (pref instanceof ListPreference) {
|
||||
((ListPreference) pref).setValue(newValue.toString());
|
||||
} else if (pref instanceof SwitchPreferenceCompat) {
|
||||
((SwitchPreferenceCompat) pref).setChecked((Boolean) newValue);
|
||||
} else {
|
||||
LOG.error("Unsupported preference type {} for confirmable handler: {}", pref.getClass(), pref);
|
||||
return;
|
||||
}
|
||||
handler.notifyPreferenceChanged(preferenceKey);
|
||||
})
|
||||
.setNegativeButton(handler.getContext().getString(R.string.Cancel), (dialog, which) -> dialog.dismiss())
|
||||
.create()
|
||||
.show();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -49,4 +49,13 @@ public interface DeviceSpecificSettingsCustomizer extends Parcelable {
|
||||
* Keys of preferences which should print its values as a summary below the preference name.
|
||||
*/
|
||||
Set<String> getPreferenceKeysWithSummary();
|
||||
|
||||
/**
|
||||
* Called when the associated {@link nodomain.freeyourgadget.gadgetbridge.impl.GBDevice} changes.
|
||||
*
|
||||
* @param handler the {@link DeviceSpecificSettingsHandler}
|
||||
*/
|
||||
default void onDeviceChanged(final DeviceSpecificSettingsHandler handler) {
|
||||
// Nothing to do by default
|
||||
}
|
||||
}
|
||||
|
||||
+42
@@ -38,12 +38,18 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PR
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.moyoung.MoyoungConstants.PREF_MOYOUNG_DEVICE_VERSION;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.moyoung.MoyoungConstants.PREF_MOYOUNG_WATCH_FACE;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputType;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
@@ -124,6 +130,42 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
setArguments(args);
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mDeviceUpdateReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
if (GBDevice.ACTION_DEVICE_CHANGED.equals(intent.getAction())) {
|
||||
final GBDevice changedDevice = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
if (changedDevice != null && changedDevice.equals(device)) {
|
||||
device = changedDevice; // update the state
|
||||
if (deviceSpecificSettingsCustomizer != null) {
|
||||
LOG.debug("{} changed, notifying customizer", changedDevice);
|
||||
deviceSpecificSettingsCustomizer.onDeviceChanged(DeviceSpecificSettingsFragment.this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View onCreateView(@NonNull final LayoutInflater inflater,
|
||||
final ViewGroup container,
|
||||
final Bundle savedInstanceState) {
|
||||
final View view = super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
||||
final IntentFilter commandFilter = new IntentFilter();
|
||||
commandFilter.addAction(GBDevice.ACTION_DEVICE_CHANGED);
|
||||
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(mDeviceUpdateReceiver, commandFilter);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(mDeviceUpdateReceiver);
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
Bundle arguments = getArguments();
|
||||
|
||||
+1
@@ -21,6 +21,7 @@ import androidx.annotation.XmlRes;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
public enum DeviceSpecificSettingsScreen {
|
||||
ADVANCED_SETTINGS("pref_screen_advanced_settings", R.xml.devicesettings_root_advanced_settings),
|
||||
ACTIVITY_INFO("pref_screen_activity_info", R.xml.devicesettings_root_activity_info),
|
||||
AUDIO("pref_screen_audio", R.xml.devicesettings_root_audio),
|
||||
AUTHENTICATION("pref_screen_authentication", R.xml.devicesettings_root_authentication),
|
||||
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/* Copyright (C) 2025 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.RunnableListIconItem;
|
||||
|
||||
public class SimpleIconListAdapter extends ArrayAdapter<RunnableListIconItem> {
|
||||
private final Context context;
|
||||
private final List<RunnableListIconItem> items;
|
||||
|
||||
public SimpleIconListAdapter(final Context context, final List<RunnableListIconItem> items) {
|
||||
super(context, R.layout.simple_list_item_with_icon, items);
|
||||
this.context = context;
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView(final int position, View convertView, @NonNull final ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = LayoutInflater.from(context);
|
||||
convertView = inflater.inflate(R.layout.simple_list_item_with_icon, parent, false);
|
||||
}
|
||||
|
||||
final ImageView icon = convertView.findViewById(R.id.option_icon);
|
||||
final TextView title = convertView.findViewById(R.id.option_title);
|
||||
|
||||
final RunnableListIconItem item = items.get(position);
|
||||
icon.setImageResource(item.getIconResId());
|
||||
title.setText(item.getTitle());
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
/* Copyright (C) 2025 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.aawireless;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.BatteryConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.aawireless.AAWirelessPrefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.aawireless.AAWirelessSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
|
||||
|
||||
public class AAWirelessCoordinator extends AbstractBLClassicDeviceCoordinator {
|
||||
@Override
|
||||
public boolean isExperimental() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deleteDevice(@NonNull final GBDevice gbDevice,
|
||||
@NonNull final Device device,
|
||||
@NonNull final DaoSession session) throws GBException {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pattern getSupportedDeviceName() {
|
||||
// AAW 1 - AAWireless-xUkL1YH0
|
||||
// AAW 2 - Normal mode: AAWireless-12345abc
|
||||
// AAW 2 - Dongle mode: AndroidAuto-AAW12345abc
|
||||
return Pattern.compile("^(AAWireless-|AndroidAuto-AAW)[0-9a-zA-Z]+$");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getManufacturer() {
|
||||
return "AAWireless";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Class<? extends DeviceSupport> getDeviceSupportClass(final GBDevice device) {
|
||||
return AAWirelessSupport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDeviceNameResource() {
|
||||
return R.string.devicetype_aawireless;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatteryCount(final GBDevice device) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BatteryConfig[] getBatteryConfig(final GBDevice device) {
|
||||
return new BatteryConfig[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceSpecificSettings getDeviceSpecificSettings(final GBDevice device) {
|
||||
final DevicePrefs devicePrefs = GBApplication.getDevicePrefs(device);
|
||||
|
||||
final DeviceSpecificSettings deviceSpecificSettings = new DeviceSpecificSettings();
|
||||
|
||||
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_aawireless_paired_phones);
|
||||
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_country);
|
||||
if (devicePrefs.getBoolean(AAWirelessPrefs.PREF_HAS_BUTTON, false)) {
|
||||
deviceSpecificSettings.addRootScreen(R.xml.devicesettings_aawireless_button);
|
||||
}
|
||||
// TODO deviceSpecificSettings.addRootScreen(R.xml.devicesettings_aawireless_auto_standby);
|
||||
|
||||
final List<Integer> advanced = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.ADVANCED_SETTINGS);
|
||||
advanced.add(R.xml.devicesettings_aawireless_advanced);
|
||||
|
||||
final List<Integer> connection = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CONNECTION);
|
||||
connection.add(R.xml.devicesettings_wifi_frequency_channel);
|
||||
|
||||
return deviceSpecificSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(final GBDevice device) {
|
||||
return new AAWirelessSettingsCustomizer();
|
||||
}
|
||||
}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
/* Copyright (C) 2025 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.aawireless;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.text.InputType;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.SimpleIconListAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.RunnableListIconItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.aawireless.AAWirelessPrefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.CountryCodeTextWatcher;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.MinMaxTextWatcher;
|
||||
|
||||
public class AAWirelessSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
|
||||
private static final String PREF_DUMMY_PHONE = "pref_aawireless_dummy_phone_";
|
||||
|
||||
@Override
|
||||
public void onPreferenceChange(final Preference preference, final DeviceSpecificSettingsHandler handler) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceChanged(final DeviceSpecificSettingsHandler handler) {
|
||||
final PreferenceCategory pairedPhonesHeader = handler.findPreference(AAWirelessPrefs.PREF_HEADER_PAIRED_PHONES);
|
||||
if (pairedPhonesHeader != null) {
|
||||
setupPhoneManagement(handler, new AAWirelessPrefs(GBApplication.getDevicePrefs(handler.getDevice()).getPreferences(), handler.getDevice()));
|
||||
}
|
||||
|
||||
setEnabledPreferences(handler);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeSettings(final DeviceSpecificSettingsHandler handler, final Prefs genericDevicePrefs, final String rootKey) {
|
||||
final AAWirelessPrefs prefs = new AAWirelessPrefs(genericDevicePrefs.getPreferences(), handler.getDevice());
|
||||
|
||||
// Paired phone management
|
||||
if (AAWirelessPrefs.PREF_SCREEN_PAIRED_PHONES.equals(rootKey)) {
|
||||
setupPhoneManagement(handler, prefs);
|
||||
return;
|
||||
}
|
||||
|
||||
// Country
|
||||
handler.addPreferenceHandlerFor(DeviceSettingsPreferenceConst.PREF_COUNTRY);
|
||||
final EditTextPreference country = handler.findPreference(DeviceSettingsPreferenceConst.PREF_COUNTRY);
|
||||
if (country != null) {
|
||||
country.setOnBindEditTextListener(editText -> {
|
||||
editText.addTextChangedListener(new CountryCodeTextWatcher(editText));
|
||||
editText.setSelection(editText.getText().length());
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-standby
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_AUTO_STANDBY_ENABLED);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_AUTO_STANDBY_DEVICE);
|
||||
|
||||
// Button modes
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_BUTTON_MODE_SINGLE_CLICK);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_BUTTON_MODE_DOUBLE_CLICK);
|
||||
appendKnownPhones(handler.findPreference(AAWirelessPrefs.PREF_BUTTON_MODE_SINGLE_CLICK), handler.getContext(), prefs);
|
||||
appendKnownPhones(handler.findPreference(AAWirelessPrefs.PREF_BUTTON_MODE_DOUBLE_CLICK), handler.getContext(), prefs);
|
||||
|
||||
// Wi-Fi frequency and channel
|
||||
final String currentFrequency = prefs.getString(DeviceSettingsPreferenceConst.PREF_WIFI_FREQUENCY, "5");
|
||||
final ListPreference wifiChannel24 = handler.findPreference(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_2_4);
|
||||
if (wifiChannel24 != null) {
|
||||
wifiChannel24.setVisible("2.4".equals(currentFrequency));
|
||||
}
|
||||
final ListPreference wifiChannel5 = handler.findPreference(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_5);
|
||||
if (wifiChannel5 != null) {
|
||||
wifiChannel5.setVisible("5".equals(currentFrequency));
|
||||
}
|
||||
handler.addPreferenceHandlerFor(DeviceSettingsPreferenceConst.PREF_WIFI_FREQUENCY, (preference, newValue) -> {
|
||||
if (wifiChannel24 != null) {
|
||||
wifiChannel24.setVisible("2.4".equals(newValue));
|
||||
}
|
||||
if (wifiChannel5 != null) {
|
||||
wifiChannel5.setVisible("5".equals(newValue));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
handler.addPreferenceHandlerFor(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_2_4);
|
||||
handler.addPreferenceHandlerFor(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_5);
|
||||
|
||||
// Advanced settings
|
||||
DeviceSettingsUtils.addConfirmablePreferenceHandlerFor(
|
||||
handler,
|
||||
AAWirelessPrefs.PREF_DONGLE_MODE,
|
||||
R.string.pref_aawireless_dongle_confirmation
|
||||
);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_PASSTHROUGH);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_AUDIO_STUTTER_FIX);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_DPI);
|
||||
final EditTextPreference dpi = handler.findPreference(AAWirelessPrefs.PREF_DPI);
|
||||
if (dpi != null) {
|
||||
dpi.setOnBindEditTextListener(editText -> {
|
||||
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
|
||||
editText.addTextChangedListener(new MinMaxTextWatcher(editText, 0, 300, false));
|
||||
editText.setSelection(editText.getText().length());
|
||||
});
|
||||
}
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_DISABLE_MEDIA_SINK);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_DISABLE_TTS_SINK);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_REMOVE_TAP_RESTRICTION);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_VAG_CRASH_FIX);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_START_FIX);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_DEVELOPER_MODE);
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_AUTO_VIDEO_FOCUS);
|
||||
|
||||
setEnabledPreferences(handler);
|
||||
}
|
||||
|
||||
private static void setEnabledPreferences(final DeviceSpecificSettingsHandler handler) {
|
||||
final boolean initialized = handler.getDevice().isInitialized();
|
||||
|
||||
setEnabled(handler.findPreference(DeviceSettingsPreferenceConst.PREF_COUNTRY), initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_AUTO_STANDBY_ENABLED), initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_AUTO_STANDBY_DEVICE), initialized);
|
||||
setEnabled(handler.findPreference(DeviceSettingsPreferenceConst.PREF_WIFI_FREQUENCY), initialized);
|
||||
setEnabled(handler.findPreference(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_2_4), initialized);
|
||||
setEnabled(handler.findPreference(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_5), initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_BUTTON_MODE_SINGLE_CLICK), initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_BUTTON_MODE_DOUBLE_CLICK), initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_DONGLE_MODE), initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_PASSTHROUGH), initialized);
|
||||
final SwitchPreferenceCompat passthroughPref = handler.findPreference(AAWirelessPrefs.PREF_PASSTHROUGH);
|
||||
final boolean passthrough = passthroughPref != null && passthroughPref.isChecked();
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_AUDIO_STUTTER_FIX), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_DPI), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_DISABLE_MEDIA_SINK), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_DISABLE_TTS_SINK), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_REMOVE_TAP_RESTRICTION), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_VAG_CRASH_FIX), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_START_FIX), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_DEVELOPER_MODE), !passthrough && initialized);
|
||||
setEnabled(handler.findPreference(AAWirelessPrefs.PREF_AUTO_VIDEO_FOCUS), !passthrough && initialized);
|
||||
}
|
||||
|
||||
private static void setEnabled(final Preference pref, final boolean enabled) {
|
||||
if (pref != null) {
|
||||
pref.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setupPhoneManagement(final DeviceSpecificSettingsHandler handler, final AAWirelessPrefs prefs) {
|
||||
final Context context = handler.getContext();
|
||||
final int phonesCount = prefs.getPairedPhoneCount();
|
||||
|
||||
final Preference preferLastConnected = handler.findPreference(AAWirelessPrefs.PREF_PREFER_LAST_CONNECTED);
|
||||
if (preferLastConnected != null) {
|
||||
handler.addPreferenceHandlerFor(AAWirelessPrefs.PREF_PREFER_LAST_CONNECTED);
|
||||
preferLastConnected.setEnabled(handler.getDevice().isInitialized());
|
||||
preferLastConnected.setVisible(!prefs.enableDongleMode());
|
||||
}
|
||||
final PreferenceCategory pairedPhonesHeader = handler.findPreference(AAWirelessPrefs.PREF_HEADER_PAIRED_PHONES);
|
||||
final Preference noPairedPhones = handler.findPreference(AAWirelessPrefs.PREF_NO_PAIRED_PHONES);
|
||||
if (noPairedPhones != null) {
|
||||
noPairedPhones.setVisible(phonesCount == 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < pairedPhonesHeader.getPreferenceCount(); i++) {
|
||||
final Preference preference = pairedPhonesHeader.getPreference(i);
|
||||
if (preference.getKey().startsWith(PREF_DUMMY_PHONE)) {
|
||||
pairedPhonesHeader.removePreference(preference);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < phonesCount; i++) {
|
||||
final int phonePosition = i;
|
||||
final Preference prefPhone = new Preference(context);
|
||||
final String phoneName = prefs.getPairedPhoneName(i);
|
||||
final String phoneMac = prefs.getPairedPhoneMac(i);
|
||||
prefPhone.setOnPreferenceClickListener(preference -> {
|
||||
final List<RunnableListIconItem> items = new ArrayList<>(4);
|
||||
|
||||
if (!prefs.enableDongleMode()) {
|
||||
items.add(new RunnableListIconItem(context.getString(R.string.switch_to_phone, phoneName), R.drawable.ic_switch_left, () -> {
|
||||
final Intent intent = new Intent(AAWirelessPrefs.ACTION_PHONE_SWITCH);
|
||||
intent.putExtra(AAWirelessPrefs.EXTRA_PHONE_MAC, phoneMac);
|
||||
intent.setPackage(BuildConfig.APPLICATION_ID);
|
||||
context.sendBroadcast(intent);
|
||||
}));
|
||||
}
|
||||
|
||||
if (phonePosition > 0) {
|
||||
items.add(new RunnableListIconItem(context.getString(R.string.widget_move_up), R.drawable.ic_arrow_upward, () -> {
|
||||
final Intent intent = new Intent(AAWirelessPrefs.ACTION_PHONE_SORT);
|
||||
intent.putExtra(AAWirelessPrefs.EXTRA_PHONE_MAC, phoneMac);
|
||||
intent.putExtra(AAWirelessPrefs.EXTRA_PHONE_NEW_POSITION, phonePosition - 1);
|
||||
intent.setPackage(BuildConfig.APPLICATION_ID);
|
||||
context.sendBroadcast(intent);
|
||||
}));
|
||||
}
|
||||
|
||||
if (phonePosition < phonesCount - 1) {
|
||||
items.add(new RunnableListIconItem(context.getString(R.string.widget_move_down), R.drawable.ic_arrow_downward, () -> {
|
||||
final Intent intent = new Intent(AAWirelessPrefs.ACTION_PHONE_SORT);
|
||||
intent.putExtra(AAWirelessPrefs.EXTRA_PHONE_MAC, phoneMac);
|
||||
intent.putExtra(AAWirelessPrefs.EXTRA_PHONE_NEW_POSITION, phonePosition + 1);
|
||||
intent.setPackage(BuildConfig.APPLICATION_ID);
|
||||
context.sendBroadcast(intent);
|
||||
}));
|
||||
}
|
||||
|
||||
items.add(new RunnableListIconItem(context.getString(R.string.Delete), R.drawable.ic_delete, () -> {
|
||||
final Intent intent = new Intent(AAWirelessPrefs.ACTION_PHONE_DELETE);
|
||||
intent.putExtra(AAWirelessPrefs.EXTRA_PHONE_MAC, phoneMac);
|
||||
intent.setPackage(BuildConfig.APPLICATION_ID);
|
||||
context.sendBroadcast(intent);
|
||||
}));
|
||||
|
||||
final SimpleIconListAdapter adapter = new SimpleIconListAdapter(context, items);
|
||||
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setAdapter(adapter, (dialog, i1) -> items.get(i1).getAction().run())
|
||||
.setTitle(phoneName)
|
||||
.setNegativeButton(android.R.string.cancel, (dialogInterface, i1) -> {
|
||||
})
|
||||
.create()
|
||||
.show();
|
||||
return true;
|
||||
});
|
||||
|
||||
prefPhone.setKey(PREF_DUMMY_PHONE + i);
|
||||
prefPhone.setIcon(R.drawable.ic_smartphone);
|
||||
prefPhone.setTitle(phoneName);
|
||||
prefPhone.setSummary(phoneMac);
|
||||
prefPhone.setEnabled(handler.getDevice().isInitialized());
|
||||
|
||||
pairedPhonesHeader.addPreference(prefPhone);
|
||||
}
|
||||
}
|
||||
|
||||
private static void appendKnownPhones(final ListPreference listPreference, final Context context, final AAWirelessPrefs prefs) {
|
||||
if (listPreference == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int phonesCount = prefs.getPairedPhoneCount();
|
||||
if (phonesCount <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CharSequence[] entries = listPreference.getEntries();
|
||||
final CharSequence[] entryValues = listPreference.getEntryValues();
|
||||
if (entries == null || entryValues == null || entries.length != entryValues.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
final CharSequence[] newEntries = new CharSequence[entries.length + phonesCount];
|
||||
final CharSequence[] newEntryValues = new CharSequence[entries.length + phonesCount];
|
||||
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
newEntries[i] = entries[i];
|
||||
newEntryValues[i] = entryValues[i];
|
||||
}
|
||||
for (int i = 0; i < phonesCount; i++) {
|
||||
final String mac = prefs.getPairedPhoneMac(i);
|
||||
final String name = prefs.getPairedPhoneName(i);
|
||||
newEntries[entries.length + i] = context.getString(R.string.switch_to_phone, name);
|
||||
newEntryValues[entries.length + i] = mac;
|
||||
}
|
||||
|
||||
listPreference.setEntries(newEntries);
|
||||
listPreference.setEntryValues(newEntryValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getPreferenceKeysWithSummary() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
public static final Creator<AAWirelessSettingsCustomizer> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public AAWirelessSettingsCustomizer createFromParcel(final Parcel in) {
|
||||
return new AAWirelessSettingsCustomizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AAWirelessSettingsCustomizer[] newArray(final int size) {
|
||||
return new AAWirelessSettingsCustomizer[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull final Parcel parcel, final int i) {
|
||||
|
||||
}
|
||||
}
|
||||
+42
-46
@@ -24,7 +24,6 @@ import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
@@ -56,7 +55,9 @@ import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractPreferenceFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.SimpleIconListAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.RunnableListIconItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSettingsService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.proto.garmin.GdiSmartProto;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
@@ -577,23 +578,50 @@ public class GarminRealtimeSettingsFragment extends AbstractPreferenceFragment {
|
||||
break;
|
||||
case 15: // sortable + delete
|
||||
// Add all sortable items and then continue
|
||||
final String moveUpStr = activity.getString(R.string.widget_move_up);
|
||||
final String moveDownStr = activity.getString(R.string.widget_move_down);
|
||||
final String deleteStr = activity.getString(R.string.appmananger_app_delete);
|
||||
|
||||
for (int i = 0; i < entry.getSortOptions().getEntriesCount(); i++) {
|
||||
final GdiSettingsService.SortEntry sortEntry = entry.getSortOptions().getEntries(i);
|
||||
final List<String> sortableOptions = new ArrayList<>(3);
|
||||
final Preference sortPref = new Preference(activity);
|
||||
final int iFinal = i;
|
||||
|
||||
final List<RunnableListIconItem> sortableOptions = new ArrayList<>(3);
|
||||
if (i > 0) {
|
||||
sortableOptions.add(moveUpStr);
|
||||
sortableOptions.add(new RunnableListIconItem(activity.getString(R.string.widget_move_up), R.drawable.ic_arrow_upward, () -> {
|
||||
sortPref.setEnabled(false);
|
||||
sendChangeRequest(
|
||||
GdiSettingsService.ChangeRequest.newBuilder()
|
||||
.setScreenId(screenId)
|
||||
.setEntryId(sortEntry.getId())
|
||||
.setPosition(GdiSettingsService.ChangeRequest.Position.newBuilder()
|
||||
.setIndex(iFinal - 1)
|
||||
)
|
||||
);
|
||||
}));
|
||||
}
|
||||
if (i < entry.getSortOptions().getEntriesCount() - 1) {
|
||||
sortableOptions.add(moveDownStr);
|
||||
sortableOptions.add(new RunnableListIconItem(activity.getString(R.string.widget_move_down), R.drawable.ic_arrow_downward, () -> {
|
||||
sortPref.setEnabled(false);
|
||||
sendChangeRequest(
|
||||
GdiSettingsService.ChangeRequest.newBuilder()
|
||||
.setScreenId(screenId)
|
||||
.setEntryId(sortEntry.getId())
|
||||
.setPosition(GdiSettingsService.ChangeRequest.Position.newBuilder()
|
||||
.setIndex(iFinal + 1)
|
||||
)
|
||||
);
|
||||
}));
|
||||
}
|
||||
sortableOptions.add(deleteStr);
|
||||
final ArrayAdapter<String> sortOptionsAdapter = new ArrayAdapter<>(activity, android.R.layout.simple_list_item_1, sortableOptions);
|
||||
final int iFinal = i;
|
||||
final Preference sortPref = new Preference(activity);
|
||||
sortableOptions.add(new RunnableListIconItem(activity.getString(R.string.appmananger_app_delete), R.drawable.ic_delete, () -> {
|
||||
sortPref.setEnabled(false);
|
||||
sendChangeRequest(
|
||||
GdiSettingsService.ChangeRequest.newBuilder()
|
||||
.setScreenId(screenId)
|
||||
.setEntryId(sortEntry.getId())
|
||||
.setPosition(GdiSettingsService.ChangeRequest.Position.newBuilder()
|
||||
.setDelete(true)
|
||||
)
|
||||
);
|
||||
}));
|
||||
final SimpleIconListAdapter sortOptionsAdapter = new SimpleIconListAdapter(activity, sortableOptions);
|
||||
sortPref.setTitle(sortEntry.getTitle().getText());
|
||||
sortPref.setPersistent(false);
|
||||
sortPref.setIconSpaceReserved(false);
|
||||
@@ -601,40 +629,8 @@ public class GarminRealtimeSettingsFragment extends AbstractPreferenceFragment {
|
||||
sortPref.setOnPreferenceClickListener(preference -> {
|
||||
new MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(sortPref.getTitle())
|
||||
.setAdapter(sortOptionsAdapter, (dialogInterface, j) -> {
|
||||
final String option = sortableOptions.get(j);
|
||||
int moveOffset = 0;
|
||||
if (option.equals(moveUpStr)) {
|
||||
moveOffset = -1;
|
||||
} else if (option.equals(moveDownStr)) {
|
||||
moveOffset = 1;
|
||||
}
|
||||
|
||||
if (moveOffset != 0) {
|
||||
sortPref.setEnabled(false);
|
||||
sendChangeRequest(
|
||||
GdiSettingsService.ChangeRequest.newBuilder()
|
||||
.setScreenId(screenId)
|
||||
.setEntryId(sortEntry.getId())
|
||||
.setPosition(GdiSettingsService.ChangeRequest.Position.newBuilder()
|
||||
.setIndex(iFinal + moveOffset)
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (option.equals(deleteStr)) {
|
||||
sortPref.setEnabled(false);
|
||||
sendChangeRequest(
|
||||
GdiSettingsService.ChangeRequest.newBuilder()
|
||||
.setScreenId(screenId)
|
||||
.setEntryId(sortEntry.getId())
|
||||
.setPosition(GdiSettingsService.ChangeRequest.Position.newBuilder()
|
||||
.setDelete(true)
|
||||
)
|
||||
);
|
||||
}
|
||||
}).setNegativeButton(android.R.string.cancel, null)
|
||||
.setAdapter(sortOptionsAdapter, (dialogInterface, j) -> sortableOptions.get(j).getAction().run())
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create().show();
|
||||
return true;
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.aawireless.AAWirelessCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.asteroidos.AsteroidOSDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.bandwpseries.BandWPSeriesDeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.banglejs.BangleJSCoordinator;
|
||||
@@ -576,6 +577,7 @@ public enum DeviceType {
|
||||
GARMIN_VIVOSMART_5(GarminVivosmart5Coordinator.class),
|
||||
GARMIN_VIVOSPORT(GarminVivosportCoordinator.class),
|
||||
GREE_AC(GreeAcCoordinator.class),
|
||||
AAWIRELESS(AAWirelessCoordinator.class),
|
||||
VIBRATISSIMO(VibratissimoCoordinator.class),
|
||||
SONY_SWR12(SonySWR12DeviceCoordinator.class),
|
||||
LIVEVIEW(LiveviewCoordinator.class),
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/* Copyright (C) 2025 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
public class RunnableListIconItem {
|
||||
private final String title;
|
||||
private final int iconResId;
|
||||
private final Runnable action;
|
||||
|
||||
public RunnableListIconItem(final String title,
|
||||
@DrawableRes final int iconResId,
|
||||
final Runnable action) {
|
||||
this.title = title;
|
||||
this.iconResId = iconResId;
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
@DrawableRes
|
||||
public int getIconResId() {
|
||||
return iconResId;
|
||||
}
|
||||
|
||||
public Runnable getAction() {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
+6
-1
@@ -50,8 +50,13 @@ public abstract class AbstractBTBRDeviceSupport extends AbstractDeviceSupport im
|
||||
|
||||
@Override
|
||||
public boolean connect() {
|
||||
final UUID supportedService = getSupportedService();
|
||||
if (supportedService == null) {
|
||||
throw new NullPointerException("No supported service UUID specified");
|
||||
}
|
||||
|
||||
if (mQueue == null) {
|
||||
mQueue = new BtBRQueue(getBluetoothAdapter(), getDevice(), getContext(), this, getSupportedService(), getBufferSize());
|
||||
mQueue = new BtBRQueue(getBluetoothAdapter(), getDevice(), getContext(), this, supportedService, getBufferSize());
|
||||
}
|
||||
return mQueue.connect();
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public final class BtBRQueue {
|
||||
}
|
||||
};
|
||||
|
||||
public BtBRQueue(BluetoothAdapter btAdapter, GBDevice gbDevice, Context context, SocketCallback socketCallback, UUID supportedService, int bufferSize) {
|
||||
public BtBRQueue(BluetoothAdapter btAdapter, GBDevice gbDevice, Context context, SocketCallback socketCallback, @NonNull UUID supportedService, int bufferSize) {
|
||||
mBtAdapter = btAdapter;
|
||||
mGbDevice = gbDevice;
|
||||
mContext = context;
|
||||
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
/* Copyright (C) 2025 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.aawireless;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.preferences.DevicePrefs;
|
||||
|
||||
public class AAWirelessPrefs extends DevicePrefs {
|
||||
// Auto-standby
|
||||
public static final String PREF_AUTO_STANDBY_ENABLED = "auto_standby_enabled";
|
||||
public static final String PREF_AUTO_STANDBY_DEVICE = "auto_standby_device";
|
||||
|
||||
// Button modes
|
||||
public static final String PREF_BUTTON_MODE_SINGLE_CLICK = "button_mode_single_click";
|
||||
public static final String PREF_BUTTON_MODE_DOUBLE_CLICK = "button_mode_double_click";
|
||||
public static final String BUTTON_MODE_NONE = "none";
|
||||
public static final String BUTTON_MODE_NEXT_PHONE = "next_phone";
|
||||
public static final String BUTTON_MODE_STANDBY_ON_OFF = "standby_on_off";
|
||||
public static final String PREF_HAS_BUTTON = "aawireless_has_button";
|
||||
|
||||
// Advanced settings
|
||||
public static final String PREF_DONGLE_MODE = "dongle_mode";
|
||||
public static final String PREF_PASSTHROUGH = "passthrough";
|
||||
public static final String PREF_AUDIO_STUTTER_FIX = "audio_stutter_fix";
|
||||
public static final String AUDIO_STUTTER_FIX_OFF = "off";
|
||||
public static final String AUDIO_STUTTER_FIX_LOW = "low";
|
||||
public static final String AUDIO_STUTTER_FIX_HIGH = "high";
|
||||
public static final String AUDIO_STUTTER_FIX_UNLIMITED = "unlimited";
|
||||
public static final String PREF_DPI = "dpi";
|
||||
public static final String PREF_DISABLE_MEDIA_SINK = "disable_media_sink";
|
||||
public static final String PREF_DISABLE_TTS_SINK = "disable_tts_sink";
|
||||
public static final String PREF_REMOVE_TAP_RESTRICTION = "remove_tap_restriction";
|
||||
public static final String PREF_VAG_CRASH_FIX = "vag_crash_fix";
|
||||
public static final String PREF_START_FIX = "start_fix";
|
||||
public static final String PREF_DEVELOPER_MODE = "developer_mode";
|
||||
public static final String PREF_AUTO_VIDEO_FOCUS = "auto_video_focus";
|
||||
|
||||
// Phone management
|
||||
public static final String PREF_PREFER_LAST_CONNECTED = "prefer_last_connected";
|
||||
public static final String PREF_SCREEN_PAIRED_PHONES = "screen_paired_phones";
|
||||
public static final String PREF_HEADER_PAIRED_PHONES = "paired_phones_header";
|
||||
public static final String PREF_NO_PAIRED_PHONES = "no_paired_phones";
|
||||
public static final String PREF_KNOWN_PHONES_COUNT = "aawireless_known_phones_count";
|
||||
public static final String PREF_KNOWN_PHONES_MAC = "aawireless_known_phones_mac_";
|
||||
public static final String PREF_KNOWN_PHONES_NAME = "aawireless_known_phones_name_";
|
||||
|
||||
// Intents
|
||||
public static final String ACTION_PHONE_SWITCH = "aawireless_action_phone_switch";
|
||||
public static final String ACTION_PHONE_SORT = "aawireless_action_phone_sort";
|
||||
public static final String ACTION_PHONE_DELETE = "aawireless_action_phone_delete";
|
||||
public static final String EXTRA_PHONE_MAC = "phone_mac";
|
||||
public static final String EXTRA_PHONE_NEW_POSITION = "phone_position";
|
||||
|
||||
public AAWirelessPrefs(final SharedPreferences preferences, final GBDevice gbDevice) {
|
||||
super(preferences, gbDevice);
|
||||
}
|
||||
|
||||
public String getCountry() {
|
||||
return getString(DeviceSettingsPreferenceConst.PREF_COUNTRY, "US");
|
||||
}
|
||||
|
||||
public boolean getAutoStandbyEnabled() {
|
||||
return getBoolean(PREF_AUTO_STANDBY_ENABLED, false);
|
||||
}
|
||||
|
||||
public String getAutoStandbyDevice() {
|
||||
return getString(PREF_AUTO_STANDBY_DEVICE, "");
|
||||
}
|
||||
|
||||
public String getButtonModeSingleClick() {
|
||||
return getString(PREF_BUTTON_MODE_SINGLE_CLICK, "none");
|
||||
}
|
||||
|
||||
public String getButtonModeDoubleClick() {
|
||||
return getString(PREF_BUTTON_MODE_DOUBLE_CLICK, "none");
|
||||
}
|
||||
|
||||
public String getWiFiFrequency() {
|
||||
return getString(DeviceSettingsPreferenceConst.PREF_WIFI_FREQUENCY, "5");
|
||||
}
|
||||
|
||||
public int getWiFiChannel() {
|
||||
return "5".equals(getWiFiFrequency()) ?
|
||||
getInt(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_5, 0) :
|
||||
getInt(DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_2_4, 0);
|
||||
}
|
||||
|
||||
public boolean enableDongleMode() {
|
||||
return getBoolean(PREF_DONGLE_MODE, false);
|
||||
}
|
||||
|
||||
public boolean enablePassthrough() {
|
||||
return getBoolean(PREF_PASSTHROUGH, true);
|
||||
}
|
||||
|
||||
public String getAudioStutterFix() {
|
||||
// off low high unlimited
|
||||
return getString(PREF_AUDIO_STUTTER_FIX, "off");
|
||||
}
|
||||
|
||||
public int getDpi() {
|
||||
// [0-300]
|
||||
return getInt(PREF_DPI, 0);
|
||||
}
|
||||
|
||||
public boolean disableMediaSink() {
|
||||
return getBoolean(PREF_DISABLE_MEDIA_SINK, false);
|
||||
}
|
||||
|
||||
public boolean disableTtsSink() {
|
||||
return getBoolean(PREF_DISABLE_TTS_SINK, false);
|
||||
}
|
||||
|
||||
public boolean removeTapRestriction() {
|
||||
return getBoolean(PREF_REMOVE_TAP_RESTRICTION, false);
|
||||
}
|
||||
|
||||
public boolean enableVagCrashFix() {
|
||||
return getBoolean(PREF_VAG_CRASH_FIX, false);
|
||||
}
|
||||
|
||||
public boolean enableStartFix() {
|
||||
return getBoolean(PREF_START_FIX, false);
|
||||
}
|
||||
|
||||
public boolean enableDeveloperMode() {
|
||||
return getBoolean(PREF_DEVELOPER_MODE, false);
|
||||
}
|
||||
|
||||
public boolean enableAutoVideoFocus() {
|
||||
return getBoolean(PREF_AUTO_VIDEO_FOCUS, false);
|
||||
}
|
||||
|
||||
public boolean preferLastConnected() {
|
||||
return getBoolean(PREF_PREFER_LAST_CONNECTED, false);
|
||||
}
|
||||
|
||||
public int getPairedPhoneCount() {
|
||||
return getInt(PREF_KNOWN_PHONES_COUNT, 0);
|
||||
}
|
||||
|
||||
public String getPairedPhoneMac(final int position) {
|
||||
return getString(PREF_KNOWN_PHONES_MAC + position, "");
|
||||
}
|
||||
|
||||
public String getPairedPhoneName(final int position) {
|
||||
return getString(PREF_KNOWN_PHONES_NAME + position, "");
|
||||
}
|
||||
}
|
||||
+441
@@ -0,0 +1,441 @@
|
||||
/* Copyright (C) 2025 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.aawireless;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdateDeviceState;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
|
||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.proto.aawireless.AAWirelessProto;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btbr.AbstractBTBRDeviceSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btbr.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class AAWirelessSupport extends AbstractBTBRDeviceSupport {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AAWirelessSupport.class);
|
||||
|
||||
private static final UUID UUID_SERVICE_AAWIRELESS = UUID.fromString("b7b2ee43-c32a-41a6-9ee4-336c1365a1c4");
|
||||
|
||||
private static final int MAX_MTU = 2048;
|
||||
|
||||
private static final String MAC_ADDR_PATTERN = "^([0-9A-F]{2}:){5}[0-9A-F]{2}$";
|
||||
|
||||
private static final short CMD_STATUS_REQUEST = 0x0001;
|
||||
private static final short CMD_STATUS_RESPONSE = 0x0002;
|
||||
private static final short CMD_SETTINGS_SET = 0x0003;
|
||||
private static final short CMD_SETTINGS_ACK = 0x0004;
|
||||
private static final short CMD_PHONE_DELETE_REQUEST = 0x000b;
|
||||
private static final short CMD_PHONE_DELETE_ACK = 0x000c;
|
||||
private static final short CMD_PHONE_POSITION_REQUEST = 0x000d;
|
||||
private static final short CMD_PHONE_POSITION_ACK = 0x000e;
|
||||
private static final short CMD_FACTORY_RESET_REQUEST = 0x000f;
|
||||
private static final short CMD_FACTORY_RESET_ACK = 0x0010;
|
||||
private static final short CMD_PHONE_SWITCH_REQUEST = 0x0011;
|
||||
private static final short CMD_PHONE_SWITCH_ACK = 0x0012;
|
||||
|
||||
private final ByteBuffer packetBuffer = ByteBuffer.allocate(MAX_MTU).order(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
private final BroadcastReceiver commandReceiver = new AAWirelessCommandReceiver();
|
||||
|
||||
public AAWirelessSupport() {
|
||||
super(LOG);
|
||||
addSupportedService(UUID_SERVICE_AAWIRELESS);
|
||||
setBufferSize(MAX_MTU);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAutoConnect() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AAWirelessPrefs getDevicePrefs() {
|
||||
return new AAWirelessPrefs(GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()), gbDevice);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TransactionBuilder initializeDevice(final TransactionBuilder builder) {
|
||||
final IntentFilter commandFilter = new IntentFilter();
|
||||
commandFilter.addAction(AAWirelessPrefs.ACTION_PHONE_SWITCH);
|
||||
commandFilter.addAction(AAWirelessPrefs.ACTION_PHONE_SORT);
|
||||
commandFilter.addAction(AAWirelessPrefs.ACTION_PHONE_DELETE);
|
||||
ContextCompat.registerReceiver(getContext(), commandReceiver, commandFilter, ContextCompat.RECEIVER_NOT_EXPORTED);
|
||||
|
||||
sendCommand(builder, CMD_STATUS_REQUEST, new byte[0]);
|
||||
return builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
try {
|
||||
getContext().unregisterReceiver(commandReceiver);
|
||||
} catch (final Exception e) {
|
||||
LOG.warn("Failed to unregister receiver", e);
|
||||
}
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSocketRead(final byte[] data) {
|
||||
packetBuffer.put(data);
|
||||
packetBuffer.flip();
|
||||
|
||||
while (packetBuffer.hasRemaining()) {
|
||||
packetBuffer.mark();
|
||||
|
||||
if (packetBuffer.remaining() < 6) {
|
||||
// not enough bytes for min packet
|
||||
packetBuffer.reset();
|
||||
break;
|
||||
}
|
||||
|
||||
final int payloadLength = packetBuffer.getInt();
|
||||
final short command = packetBuffer.getShort();
|
||||
|
||||
if (packetBuffer.remaining() < payloadLength) {
|
||||
// not enough bytes for payload
|
||||
packetBuffer.reset();
|
||||
break;
|
||||
}
|
||||
|
||||
final byte[] payload = new byte[payloadLength];
|
||||
packetBuffer.get(payload);
|
||||
|
||||
try {
|
||||
handleCommand(command, payload);
|
||||
} catch (final Exception e) {
|
||||
LOG.error("Failed to handle command", e);
|
||||
}
|
||||
}
|
||||
|
||||
packetBuffer.compact();
|
||||
}
|
||||
|
||||
private void sendCommand(final TransactionBuilder builder, final short command, final byte[] payload) {
|
||||
final ByteBuffer buf = ByteBuffer.allocate(payload.length + 6).order(ByteOrder.BIG_ENDIAN);
|
||||
buf.putInt(payload.length);
|
||||
buf.putShort(command);
|
||||
buf.put(payload);
|
||||
|
||||
builder.write(buf.array());
|
||||
}
|
||||
|
||||
private void sendCommand(final String taskName, final short command, final byte[] payload) {
|
||||
final TransactionBuilder builder = createTransactionBuilder(taskName);
|
||||
sendCommand(builder, command, payload);
|
||||
builder.queue(getQueue());
|
||||
}
|
||||
|
||||
private void handleCommand(final short command, final byte[] payload) throws Exception {
|
||||
switch (command) {
|
||||
case CMD_STATUS_RESPONSE -> {
|
||||
final AAWirelessProto.Status status = AAWirelessProto.Status.parseFrom(payload);
|
||||
LOG.info("Got status = {}", status);
|
||||
handleStatus(status);
|
||||
}
|
||||
case CMD_SETTINGS_ACK -> {
|
||||
final AAWirelessProto.Ack ack = AAWirelessProto.Ack.parseFrom(payload);
|
||||
LOG.info("Got settings ack, status={}, message={}", ack.getStatus(), ack.getMessage());
|
||||
if (ack.getStatus() != 0) {
|
||||
GB.toast("AAW " + ack.getStatus() + ": " + ack.getMessage(), Toast.LENGTH_LONG, GB.WARN);
|
||||
}
|
||||
sendCommand("request status", CMD_STATUS_REQUEST, new byte[0]);
|
||||
}
|
||||
case CMD_PHONE_DELETE_ACK -> {
|
||||
final AAWirelessProto.Ack ack = AAWirelessProto.Ack.parseFrom(payload);
|
||||
LOG.info("Got Phone delete ack, status={}, message={}", ack.getStatus(), ack.getMessage());
|
||||
if (ack.getStatus() != 0) {
|
||||
GB.toast("AAW " + ack.getStatus() + ": " + ack.getMessage(), Toast.LENGTH_LONG, GB.WARN);
|
||||
}
|
||||
sendCommand("request status", CMD_STATUS_REQUEST, new byte[0]);
|
||||
}
|
||||
case CMD_PHONE_POSITION_ACK -> {
|
||||
final AAWirelessProto.Ack ack = AAWirelessProto.Ack.parseFrom(payload);
|
||||
LOG.info("Got phone position ack, status={}, message={}", ack.getStatus(), ack.getMessage());
|
||||
if (ack.getStatus() != 0) {
|
||||
GB.toast("AAW " + ack.getStatus() + ": " + ack.getMessage(), Toast.LENGTH_LONG, GB.WARN);
|
||||
}
|
||||
sendCommand("request status", CMD_STATUS_REQUEST, new byte[0]);
|
||||
}
|
||||
case CMD_FACTORY_RESET_ACK -> {
|
||||
final AAWirelessProto.Ack ack = AAWirelessProto.Ack.parseFrom(payload);
|
||||
LOG.info("Got factory reset ack, status={}, message={}", ack.getStatus(), ack.getMessage());
|
||||
if (ack.getStatus() != 0) {
|
||||
GB.toast("AAW " + ack.getStatus() + ": " + ack.getMessage(), Toast.LENGTH_LONG, GB.WARN);
|
||||
}
|
||||
}
|
||||
case CMD_PHONE_SWITCH_ACK -> {
|
||||
final AAWirelessProto.Ack ack = AAWirelessProto.Ack.parseFrom(payload);
|
||||
LOG.info("Got phone switch ack, status={}, message={}", ack.getStatus(), ack.getMessage());
|
||||
if (ack.getStatus() != 0) {
|
||||
GB.toast("AAW " + ack.getStatus() + ": " + ack.getMessage(), Toast.LENGTH_LONG, GB.WARN);
|
||||
}
|
||||
}
|
||||
default -> LOG.warn(
|
||||
"Got unknown command {}, payload={}",
|
||||
String.format("0x%04x", command),
|
||||
GB.hexdump(payload)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleStatus(final AAWirelessProto.Status status) {
|
||||
// FW / HW
|
||||
final GBDeviceEventVersionInfo versionInfoEvent = new GBDeviceEventVersionInfo();
|
||||
versionInfoEvent.hwVersion = status.getHardwareModel();
|
||||
versionInfoEvent.fwVersion = status.getFirmwareVersion();
|
||||
evaluateGBDeviceEvent(versionInfoEvent);
|
||||
|
||||
// Mark as initialized
|
||||
evaluateGBDeviceEvent(new GBDeviceEventUpdateDeviceState(GBDevice.State.INITIALIZED));
|
||||
|
||||
// Settings
|
||||
final AAWirelessProto.Settings settings = status.getSettings();
|
||||
final GBDeviceEventUpdatePreferences preferencesEvent = new GBDeviceEventUpdatePreferences();
|
||||
preferencesEvent.withPreference(DeviceSettingsPreferenceConst.PREF_COUNTRY, settings.getCountry());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_AUTO_STANDBY_ENABLED, settings.getAutoStandbyEnabled());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_AUTO_STANDBY_DEVICE, settings.getAutoStandbyDevice());
|
||||
preferencesEvent.withPreference(
|
||||
DeviceSettingsPreferenceConst.PREF_WIFI_FREQUENCY,
|
||||
settings.getWifiFrequency() == AAWirelessProto.WiFiFrequency.FREQ_2_4_GHZ ? "2.4" : "5"
|
||||
);
|
||||
switch (settings.getWifiFrequency()) {
|
||||
case FREQ_5_GHZ -> preferencesEvent.withPreference(
|
||||
DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_5,
|
||||
String.valueOf(settings.getWifiChannel())
|
||||
);
|
||||
case FREQ_2_4_GHZ -> preferencesEvent.withPreference(
|
||||
DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_2_4,
|
||||
String.valueOf(settings.getWifiChannel())
|
||||
);
|
||||
}
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_HAS_BUTTON, settings.hasButtonsConfig());
|
||||
if (settings.hasButtonsConfig()) {
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_BUTTON_MODE_SINGLE_CLICK, buttonModeToPref(settings.getButtonsConfig().getSingle()));
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_BUTTON_MODE_DOUBLE_CLICK, buttonModeToPref(settings.getButtonsConfig().getDouble()));
|
||||
}
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_DONGLE_MODE, settings.getDongleMode());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_PASSTHROUGH, settings.getPassthrough());
|
||||
final String audioStutterFixPrefValue;
|
||||
if (settings.getAudioStutterFix() == 50) {
|
||||
audioStutterFixPrefValue = AAWirelessPrefs.AUDIO_STUTTER_FIX_LOW;
|
||||
} else if (settings.getAudioStutterFix() == 100) {
|
||||
audioStutterFixPrefValue = AAWirelessPrefs.AUDIO_STUTTER_FIX_HIGH;
|
||||
} else if (settings.getAudioStutterFix() == 4096) {
|
||||
audioStutterFixPrefValue = AAWirelessPrefs.AUDIO_STUTTER_FIX_UNLIMITED;
|
||||
} else {
|
||||
audioStutterFixPrefValue = AAWirelessPrefs.AUDIO_STUTTER_FIX_OFF;
|
||||
}
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_AUDIO_STUTTER_FIX, audioStutterFixPrefValue);
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_DPI, String.valueOf(settings.getDpi()));
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_DISABLE_MEDIA_SINK, settings.getDisableMediaSink());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_DISABLE_TTS_SINK, settings.getDisableTtsSink());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_REMOVE_TAP_RESTRICTION, settings.getRemoveTapRestriction());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_VAG_CRASH_FIX, settings.getVagCrashFix());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_START_FIX, settings.getStartFix());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_DEVELOPER_MODE, settings.getDeveloperMode());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_AUTO_VIDEO_FOCUS, settings.getAutoVideoFocus());
|
||||
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_PREFER_LAST_CONNECTED, settings.getPreferLastConnectedPhone());
|
||||
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_KNOWN_PHONES_COUNT, status.getPairedPhoneCount());
|
||||
for (int i = 0; i < status.getPairedPhoneCount(); i++) {
|
||||
final AAWirelessProto.Phone phone = status.getPairedPhone(i);
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_KNOWN_PHONES_MAC + i, phone.getMacAddress());
|
||||
preferencesEvent.withPreference(AAWirelessPrefs.PREF_KNOWN_PHONES_NAME + i, phone.getName());
|
||||
}
|
||||
|
||||
evaluateGBDeviceEvent(preferencesEvent);
|
||||
}
|
||||
|
||||
private String buttonModeToPref(final AAWirelessProto.ButtonMode buttonMode) {
|
||||
if (buttonMode.hasNextPhone()) {
|
||||
return AAWirelessPrefs.BUTTON_MODE_NEXT_PHONE;
|
||||
} else if (buttonMode.hasSelectPhone()) {
|
||||
return buttonMode.getSelectPhone().getMacAddress();
|
||||
} else if (buttonMode.hasStandbyOnOff()) {
|
||||
return AAWirelessPrefs.BUTTON_MODE_STANDBY_ON_OFF;
|
||||
} else {
|
||||
return AAWirelessPrefs.BUTTON_MODE_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
private AAWirelessProto.ButtonMode prefToButtonMode(final String prefValue) {
|
||||
final AAWirelessProto.ButtonMode.Builder builder = AAWirelessProto.ButtonMode.newBuilder();
|
||||
switch (prefValue) {
|
||||
case AAWirelessPrefs.BUTTON_MODE_NEXT_PHONE:
|
||||
builder.setNextPhone("");
|
||||
break;
|
||||
case AAWirelessPrefs.BUTTON_MODE_STANDBY_ON_OFF:
|
||||
builder.setStandbyOnOff("");
|
||||
break;
|
||||
case AAWirelessPrefs.BUTTON_MODE_NONE:
|
||||
break;
|
||||
default:
|
||||
if (prefValue.matches(MAC_ADDR_PATTERN)) {
|
||||
builder.setSelectPhone(AAWirelessProto.Phone.newBuilder().setMacAddress(prefValue));
|
||||
} else {
|
||||
LOG.warn("Unexpected button mode preference value {}", prefValue);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendConfiguration(final String config) {
|
||||
switch (config) {
|
||||
case DeviceSettingsPreferenceConst.PREF_COUNTRY:
|
||||
case AAWirelessPrefs.PREF_AUTO_STANDBY_ENABLED:
|
||||
case AAWirelessPrefs.PREF_AUTO_STANDBY_DEVICE:
|
||||
case DeviceSettingsPreferenceConst.PREF_WIFI_FREQUENCY:
|
||||
case DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_2_4:
|
||||
case DeviceSettingsPreferenceConst.PREF_WIFI_CHANNEL_5:
|
||||
case AAWirelessPrefs.PREF_BUTTON_MODE_SINGLE_CLICK:
|
||||
case AAWirelessPrefs.PREF_BUTTON_MODE_DOUBLE_CLICK:
|
||||
case AAWirelessPrefs.PREF_DONGLE_MODE:
|
||||
case AAWirelessPrefs.PREF_PASSTHROUGH:
|
||||
case AAWirelessPrefs.PREF_AUDIO_STUTTER_FIX:
|
||||
case AAWirelessPrefs.PREF_DPI:
|
||||
case AAWirelessPrefs.PREF_DISABLE_MEDIA_SINK:
|
||||
case AAWirelessPrefs.PREF_DISABLE_TTS_SINK:
|
||||
case AAWirelessPrefs.PREF_REMOVE_TAP_RESTRICTION:
|
||||
case AAWirelessPrefs.PREF_VAG_CRASH_FIX:
|
||||
case AAWirelessPrefs.PREF_START_FIX:
|
||||
case AAWirelessPrefs.PREF_DEVELOPER_MODE:
|
||||
case AAWirelessPrefs.PREF_AUTO_VIDEO_FOCUS:
|
||||
sendSettings();
|
||||
return;
|
||||
}
|
||||
|
||||
super.onSendConfiguration(config);
|
||||
}
|
||||
|
||||
private void sendSettings() {
|
||||
final AAWirelessPrefs prefs = getDevicePrefs();
|
||||
|
||||
final AAWirelessProto.WiFiFrequency wiFiFrequency = switch (prefs.getWiFiFrequency()) {
|
||||
case "5" -> AAWirelessProto.WiFiFrequency.FREQ_5_GHZ;
|
||||
case "2.4" -> AAWirelessProto.WiFiFrequency.FREQ_2_4_GHZ;
|
||||
default -> throw new IllegalArgumentException(
|
||||
"Unknown wifi frequency " + prefs.getWiFiFrequency()
|
||||
);
|
||||
};
|
||||
|
||||
final long audioStutterFix = switch (prefs.getAudioStutterFix()) {
|
||||
case "unlimited" -> 4096;
|
||||
case "high" -> 100;
|
||||
case "low" -> 50;
|
||||
case "off" -> -1; // 18446744073709551615 in uint64
|
||||
default -> throw new IllegalArgumentException(
|
||||
"Unknown audio stutter fix " + prefs.getAudioStutterFix()
|
||||
);
|
||||
};
|
||||
|
||||
final AAWirelessProto.ButtonsConfig buttonsConfig = AAWirelessProto.ButtonsConfig.newBuilder()
|
||||
.setSingle(prefToButtonMode(prefs.getButtonModeSingleClick()))
|
||||
.setDouble(prefToButtonMode(prefs.getButtonModeDoubleClick()))
|
||||
.build();
|
||||
|
||||
final AAWirelessProto.Settings.Builder builder = AAWirelessProto.Settings.newBuilder()
|
||||
.setPassthrough(prefs.enablePassthrough())
|
||||
.setVagCrashFix(prefs.enableVagCrashFix())
|
||||
.setDpi(prefs.getDpi())
|
||||
.setRemoveTapRestriction(prefs.removeTapRestriction())
|
||||
.setDeveloperMode(prefs.enableDeveloperMode())
|
||||
.setDisableMediaSink(prefs.disableMediaSink())
|
||||
.setWifiFrequency(wiFiFrequency)
|
||||
.setAutoVideoFocus(prefs.enableAutoVideoFocus())
|
||||
.setWifiChannel(prefs.getWiFiChannel())
|
||||
.setCountry(prefs.getCountry())
|
||||
.setPreferLastConnectedPhone(prefs.preferLastConnected())
|
||||
.setDisableTtsSink(prefs.disableTtsSink())
|
||||
.setDongleMode(prefs.enableDongleMode())
|
||||
.setAutoStandbyDevice(prefs.getAutoStandbyDevice())
|
||||
.setStartFix(prefs.enableStartFix())
|
||||
.setAudioStutterFix(audioStutterFix)
|
||||
.setButtonsConfig(buttonsConfig)
|
||||
.setAutoStandbyEnabled(prefs.getAutoStandbyEnabled());
|
||||
|
||||
sendCommand("send settings", CMD_SETTINGS_SET, builder.build().toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReset(final int flags) {
|
||||
if ((flags & GBDeviceProtocol.RESET_FLAGS_FACTORY_RESET) != 0) {
|
||||
sendCommand("factory reset", CMD_FACTORY_RESET_REQUEST, new byte[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private class AAWirelessCommandReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String mac = intent.getStringExtra(AAWirelessPrefs.EXTRA_PHONE_MAC);
|
||||
|
||||
switch (action) {
|
||||
case AAWirelessPrefs.ACTION_PHONE_SWITCH: {
|
||||
LOG.debug("Switch phone to {}", mac);
|
||||
final AAWirelessProto.Phone payload = AAWirelessProto.Phone.newBuilder().setMacAddress(mac).build();
|
||||
sendCommand("switch phone", CMD_PHONE_SWITCH_REQUEST, payload.toByteArray());
|
||||
return;
|
||||
}
|
||||
case AAWirelessPrefs.ACTION_PHONE_SORT: {
|
||||
final int newPosition = intent.getIntExtra(AAWirelessPrefs.EXTRA_PHONE_NEW_POSITION, 0);
|
||||
LOG.debug("Sort phone {} to {}", mac, newPosition);
|
||||
final AAWirelessProto.PhonePosition payload = AAWirelessProto.PhonePosition.newBuilder()
|
||||
.setMacAddress(mac)
|
||||
.setPosition(newPosition)
|
||||
.build();
|
||||
sendCommand("set phone position", CMD_PHONE_POSITION_REQUEST, payload.toByteArray());
|
||||
return;
|
||||
}
|
||||
case AAWirelessPrefs.ACTION_PHONE_DELETE: {
|
||||
final AAWirelessProto.Phone payload = AAWirelessProto.Phone.newBuilder().setMacAddress(mac).build();
|
||||
LOG.debug("Delete phone {}", mac);
|
||||
sendCommand("delete phone", CMD_PHONE_DELETE_REQUEST, payload.toByteArray());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LOG.warn("Unknown action {}", action);
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-44
@@ -8,12 +8,10 @@ import android.os.Parcel;
|
||||
import android.text.InputFilter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.EditTextPreference;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SeekBarPreference;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -26,6 +24,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
@@ -39,7 +38,7 @@ public class EarFunSettingsCustomizer implements DeviceSpecificSettingsCustomize
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public static final Creator<EarFunSettingsCustomizer> CREATOR = new Creator<EarFunSettingsCustomizer>() {
|
||||
public static final Creator<EarFunSettingsCustomizer> CREATOR = new Creator<>() {
|
||||
@Override
|
||||
public EarFunSettingsCustomizer createFromParcel(final Parcel in) {
|
||||
final GBDevice device = in.readParcelable(EarFunSettingsCustomizer.class.getClassLoader());
|
||||
@@ -60,7 +59,7 @@ public class EarFunSettingsCustomizer implements DeviceSpecificSettingsCustomize
|
||||
|
||||
@Override
|
||||
public void customizeSettings(DeviceSpecificSettingsHandler handler, Prefs prefs, String rootKey) {
|
||||
addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_DEVICE_NAME, R.string.prefs_device_name, R.string.earfun_change_device_name_confirm_message);
|
||||
DeviceSettingsUtils.addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_DEVICE_NAME, R.string.earfun_change_device_name_confirm_message);
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_AMBIENT_SOUND_CONTROL);
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_TRANSPARENCY_MODE);
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_ANC_MODE);
|
||||
@@ -87,12 +86,12 @@ public class EarFunSettingsCustomizer implements DeviceSpecificSettingsCustomize
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_EQUALIZER_BAND_16000);
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_IN_EAR_DETECTION_MODE);
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_TOUCH_MODE);
|
||||
addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_CONNECT_TWO_DEVICES_MODE, R.string.earfun_connect_two_devices, R.string.earfun_reboot_confirm_message);
|
||||
addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_ADVANCED_AUDIO_MODE, R.string.earfun_advanced_audio_mode, R.string.earfun_reboot_confirm_message);
|
||||
addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_MICROPHONE_MODE, R.string.earfun_microphone_mode, R.string.earfun_reboot_confirm_message);
|
||||
DeviceSettingsUtils.addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_CONNECT_TWO_DEVICES_MODE, R.string.earfun_reboot_confirm_message);
|
||||
DeviceSettingsUtils.addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_ADVANCED_AUDIO_MODE, R.string.earfun_reboot_confirm_message);
|
||||
DeviceSettingsUtils.addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_MICROPHONE_MODE, R.string.earfun_reboot_confirm_message);
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_FIND_DEVICE);
|
||||
handler.addPreferenceHandlerFor(PREF_EARFUN_VOICE_PROMPT_VOLUME);
|
||||
addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_AUDIO_CODEC, R.string.audio_codec, R.string.earfun_reboot_confirm_message);
|
||||
DeviceSettingsUtils.addConfirmablePreferenceHandlerFor(handler, PREF_EARFUN_AUDIO_CODEC, R.string.earfun_reboot_confirm_message);
|
||||
|
||||
EditTextPreference editTextDeviceName = handler.findPreference(PREF_EARFUN_DEVICE_NAME);
|
||||
if (editTextDeviceName != null) {
|
||||
@@ -103,42 +102,6 @@ public class EarFunSettingsCustomizer implements DeviceSpecificSettingsCustomize
|
||||
}
|
||||
}
|
||||
|
||||
protected void addConfirmablePreferenceHandlerFor(DeviceSpecificSettingsHandler handler, final String preferenceKey, int alertPreferenceNAme, int alertMessage) {
|
||||
Preference pref = handler.findPreference(preferenceKey);
|
||||
Context context = handler.getContext();
|
||||
if (pref != null) {
|
||||
pref.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||
String preferenceName = context.getString(alertPreferenceNAme);
|
||||
String title = context.getString(R.string.earfun_change_confirm_title, preferenceName);
|
||||
String message = context.getString(alertMessage);
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(handler.getContext().getString(R.string.ok), (dialog, which) -> {
|
||||
if (pref instanceof EditTextPreference) {
|
||||
((EditTextPreference) pref).setText(newValue.toString());
|
||||
}
|
||||
if (pref instanceof ListPreference) {
|
||||
((ListPreference) pref).setValue(newValue.toString());
|
||||
}
|
||||
if (pref instanceof SwitchPreferenceCompat) {
|
||||
((SwitchPreferenceCompat) pref).setChecked((Boolean) newValue);
|
||||
} else {
|
||||
LOG.error("unsupported preference type for confirmable handler: {}", pref);
|
||||
}
|
||||
handler.notifyPreferenceChanged(preferenceKey);
|
||||
})
|
||||
.setNegativeButton(handler.getContext().getString(R.string.Cancel), (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
})
|
||||
.create()
|
||||
.show();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
protected void initializeEqualizerPresetListPreference(DeviceSpecificSettingsHandler handler,
|
||||
Equalizer.EqualizerPreset[] equalizerPresets) {
|
||||
ListPreference equalizerPresetListPreference = handler.findPreference(PREF_EARFUN_EQUALIZER_PRESET);
|
||||
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/* Copyright (C) 2025 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.util.preferences;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class CountryCodeTextWatcher implements TextWatcher {
|
||||
private final EditText editText;
|
||||
|
||||
public CountryCodeTextWatcher(final EditText editText) {
|
||||
this.editText = editText;
|
||||
}
|
||||
|
||||
@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 editable) {
|
||||
editText.removeTextChangedListener(this);
|
||||
|
||||
final StringBuilder filtered = new StringBuilder();
|
||||
for (int i = 0; i < editable.length(); i++) {
|
||||
final char c = Character.toUpperCase(editable.charAt(i));
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
filtered.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
String newText = filtered.toString();
|
||||
if (newText.length() > 2) {
|
||||
newText = newText.substring(0, 2);
|
||||
}
|
||||
|
||||
if (!newText.equals(editable.toString())) {
|
||||
editText.setText(newText);
|
||||
editText.setSelection(newText.length());
|
||||
}
|
||||
|
||||
editText.addTextChangedListener(this);
|
||||
editText.getRootView().findViewById(android.R.id.button1).setEnabled(editText.getText().length() == 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package aawireless;
|
||||
|
||||
option java_package = "nodomain.freeyourgadget.gadgetbridge.proto.aawireless";
|
||||
option java_outer_classname = "AAWirelessProto";
|
||||
|
||||
message Status {
|
||||
optional string macAddress = 1;
|
||||
optional string firmwareVersion = 2;
|
||||
optional Settings settings = 3;
|
||||
optional CarInfo carInfo = 4;
|
||||
optional string hardwareModel = 5;
|
||||
repeated Phone pairedPhone = 11;
|
||||
}
|
||||
|
||||
message Phone {
|
||||
optional string macAddress = 1;
|
||||
optional string name = 2;
|
||||
optional uint32 position = 3; // 0,1,2...
|
||||
optional bool current = 4; // 0/1 - current device? (might not be the connected one)
|
||||
optional uint32 unk5 = 5; // 0
|
||||
}
|
||||
|
||||
message PhonePosition {
|
||||
optional string macAddress = 1;
|
||||
optional uint32 position = 2;
|
||||
}
|
||||
|
||||
message CarInfo {
|
||||
}
|
||||
|
||||
enum WiFiFrequency {
|
||||
FREQ_5_GHZ = 0;
|
||||
FREQ_2_4_GHZ = 1;
|
||||
}
|
||||
|
||||
message Settings {
|
||||
optional uint32 unk1 = 1; // 0
|
||||
optional uint32 unk2 = 2; // 0
|
||||
optional bool passthrough = 3;
|
||||
optional bool vagCrashFix = 4;
|
||||
optional uint32 dpi = 5; // [0,300]
|
||||
optional bool removeTapRestriction = 6;
|
||||
optional bool developerMode = 7;
|
||||
optional bool disableMediaSink = 8;
|
||||
optional uint32 unk9 = 9; // 0
|
||||
optional WiFiFrequency wifiFrequency = 10;
|
||||
optional bool autoVideoFocus = 11;
|
||||
optional uint32 unk12 = 12; // 20000
|
||||
optional uint32 unk13 = 13; // 0
|
||||
optional string unk14 = 14; // ""
|
||||
optional string unk15 = 15; // ""
|
||||
optional uint32 wifiChannel = 16;
|
||||
optional uint32 unk17 = 17; // 0
|
||||
optional string country = 18; // 2-letter
|
||||
optional bool preferLastConnectedPhone = 19;
|
||||
optional bool disableTtsSink = 20;
|
||||
optional bool dongleMode = 21;
|
||||
optional string autoStandbyDevice = 22; // mac address
|
||||
optional uint32 unk23 = 23; // 0
|
||||
optional uint32 unk24 = 24; // 0
|
||||
optional bool startFix = 25;
|
||||
// 26 is some byte array?
|
||||
optional uint32 unk27 = 27; // 0
|
||||
optional uint32 unk28 = 28; // 0
|
||||
optional uint32 unk29 = 29; // 0
|
||||
optional uint32 unk30 = 30; // 0
|
||||
optional uint64 audioStutterFix = 31; // off 18446744073709551615, low 50, high 100, unlimited 4096
|
||||
optional uint32 unk32 = 32; // 0
|
||||
optional uint32 unk33 = 33; // 1
|
||||
optional uint32 unk34 = 34; // 0
|
||||
optional ButtonsConfig buttonsConfig = 35;
|
||||
optional bool autoStandbyEnabled = 37;
|
||||
}
|
||||
|
||||
message ButtonsConfig {
|
||||
optional ButtonMode single = 1;
|
||||
optional ButtonMode double = 2;
|
||||
optional ButtonMode unk4 = 4; // { 1: "" }
|
||||
}
|
||||
|
||||
message ButtonMode {
|
||||
// only the desired one is set, nothing set for no action
|
||||
optional string nextPhone = 2; // ""
|
||||
optional Phone selectPhone = 3; // only mac address
|
||||
optional string standbyOnOff = 4; // ""
|
||||
}
|
||||
|
||||
message Ack {
|
||||
optional uint32 status = 1; // 0 for success?
|
||||
optional string message = 2; // "" - error msg?
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#7E7E7E"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#7E7E7E"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#7E7E7E"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M440,647L440,200Q440,183 451.5,171.5Q463,160 480,160Q497,160 508.5,171.5Q520,183 520,200L520,647L716,451Q728,439 744,439.5Q760,440 772,452Q783,464 783.5,480Q784,496 772,508L508,772Q502,778 495,780.5Q488,783 480,783Q472,783 465,780.5Q458,778 452,772L188,508Q177,497 177,480.5Q177,464 188,452Q200,440 216.5,440Q233,440 245,452L440,647Z" />
|
||||
|
||||
</vector>
|
||||
@@ -1,7 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#7E7E7E"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#7E7E7E"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<!--
|
||||
Licensed under public domain
|
||||
https://www.svgrepo.com/svg/467868/frequency-2
|
||||
-->
|
||||
|
||||
<path
|
||||
android:pathData="M21,12l-4,0l-2,4l-4,-8l-3,7l-2,-3l-3,0"
|
||||
android:strokeWidth="2"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round" />
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,17 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
|
||||
<!--
|
||||
Licensed under the public domain.
|
||||
https://www.svgrepo.com/svg/478225/smartphone-material
|
||||
-->
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M355.3,0H156.69C125.38,0 100,25.38 100,56.69v398.63C100,486.63 125.38,512 156.69,512h198.61C386.61,512 412,486.63 412,455.31V56.69C412,25.38 386.61,0 355.3,0zM256,483.98c-8.09,0 -14.67,-6.56 -14.67,-14.67c0,-8.09 6.58,-14.66 14.67,-14.66s14.67,6.56 14.67,14.66C270.67,477.42 264.09,483.98 256,483.98zM364,424H148V64h216V424z" />
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,29 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
|
||||
<!--
|
||||
Licensed under public domain
|
||||
https://www.svgrepo.com/svg/478147/usb-free-material
|
||||
-->
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M10.46,295.6c-14.02,14.02 -13.93,36.91 0.18,51.02l154.73,154.74c6.86,6.86 15.98,10.64 25.68,10.64h0c9.59,0 18.59,-3.71 25.34,-10.46L407.64,310.29L201.7,104.36L10.46,295.6zM100.48,296.98c-3.31,0 -6.42,-1.29 -8.76,-3.63l-1.78,-1.78c-2.34,-2.34 -3.63,-5.45 -3.63,-8.76c0,-3.31 1.29,-6.43 3.63,-8.77l97.64,-97.64c2.34,-2.34 5.45,-3.63 8.77,-3.63c3.31,0 6.43,1.29 8.77,3.63l1.77,1.77c4.83,4.83 4.83,12.7 0,17.53l-97.64,97.64C106.9,295.69 103.79,296.98 100.48,296.98z" />
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M508.68,153.91L358.09,3.32C355.95,1.18 353.11,0 350.1,0c-3.02,0 -5.86,1.18 -8,3.32L240.69,104.73l23.6,23.59l85.81,-85.81l119.38,119.38l-85.81,85.81l23.6,23.59l101.41,-101.41c2.13,-2.13 3.31,-4.96 3.32,-7.97C512.01,158.91 510.83,156.06 508.68,153.91z" />
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M335.78,156.91l-34.38,-34.38l34.16,-34.16l34.38,34.38z" />
|
||||
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M423.56,176.05l-34.15,-34.15l-34.16,34.15l34.16,34.16z" />
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/option_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:contentDescription="@string/app_name" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/option_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?attr/textAppearanceListItem" />
|
||||
</LinearLayout>
|
||||
@@ -230,6 +230,95 @@
|
||||
<item>buttons_on_right</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="wifi_frequency_names">
|
||||
<item>@string/wifi_frequency_2_4_ghz</item>
|
||||
<item>@string/wifi_frequency_5_ghz</item>
|
||||
</string-array>
|
||||
<string-array name="wifi_frequency_values">
|
||||
<item>2.4</item>
|
||||
<item>5</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="aawireless_audio_stutter_fix_names">
|
||||
<item>@string/off</item>
|
||||
<item>@string/pref_aawireless_audio_stutter_fix_low</item>
|
||||
<item>@string/pref_aawireless_audio_stutter_fix_high</item>
|
||||
<item>@string/pref_aawireless_audio_stutter_fix_unlimited</item>
|
||||
</string-array>
|
||||
<string-array name="aawireless_audio_stutter_fix_values">
|
||||
<item>off</item>
|
||||
<item>low</item>
|
||||
<item>high</item>
|
||||
<item>unlimited</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="aawireless_click_names">
|
||||
<item>@string/none</item>
|
||||
<item>@string/switch_to_next_phone</item>
|
||||
<item>@string/toggle_standby_on_off</item>
|
||||
</string-array>
|
||||
<string-array name="aawireless_click_values">
|
||||
<item>none</item>
|
||||
<item>next_phone</item>
|
||||
<item>standby_on_off</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="wifi_channels_2_4_ghz">
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
<item>5</item>
|
||||
<item>6</item>
|
||||
<item>7</item>
|
||||
<item>8</item>
|
||||
<item>9</item>
|
||||
<item>10</item>
|
||||
<item>11</item>
|
||||
<item>12</item>
|
||||
<item>13</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="wifi_channels_5_ghz">
|
||||
<item>32</item>
|
||||
<item>36</item>
|
||||
<item>40</item>
|
||||
<item>44</item>
|
||||
<item>48</item>
|
||||
<item>52</item>
|
||||
<item>56</item>
|
||||
<item>60</item>
|
||||
<item>64</item>
|
||||
<item>68</item>
|
||||
<item>72</item>
|
||||
<item>76</item>
|
||||
<item>80</item>
|
||||
<item>84</item>
|
||||
<item>88</item>
|
||||
<item>92</item>
|
||||
<item>96</item>
|
||||
<item>100</item>
|
||||
<item>104</item>
|
||||
<item>108</item>
|
||||
<item>112</item>
|
||||
<item>116</item>
|
||||
<item>120</item>
|
||||
<item>124</item>
|
||||
<item>128</item>
|
||||
<item>132</item>
|
||||
<item>136</item>
|
||||
<item>140</item>
|
||||
<item>144</item>
|
||||
<item>149</item>
|
||||
<item>153</item>
|
||||
<item>157</item>
|
||||
<item>161</item>
|
||||
<item>165</item>
|
||||
<item>169</item>
|
||||
<item>173</item>
|
||||
<item>177</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="wearmode">
|
||||
<item>@string/wearmode_band</item>
|
||||
<item>@string/wearmode_pebble</item>
|
||||
|
||||
@@ -2008,6 +2008,7 @@
|
||||
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
|
||||
<string name="devicetype_redmi_watch_5_active">Redmi Watch 5 Active</string>
|
||||
<string name="devicetype_redmi_watch_5_lite">Redmi Watch 5 Lite</string>
|
||||
<string name="devicetype_aawireless">AAWireless</string>
|
||||
<string name="devicetype_colmi_r02">Colmi R02</string>
|
||||
<string name="devicetype_colmi_r03">Colmi R03</string>
|
||||
<string name="devicetype_colmi_r06">Colmi R06</string>
|
||||
@@ -4009,5 +4010,51 @@
|
||||
<string name="even_realities_frame_description">%1$s %2$s (%3$s: %4$s)</string>
|
||||
<string name="even_realities_left_lens">Left Lens</string>
|
||||
<string name="even_realities_right_lens">Right Lens</string>
|
||||
|
||||
<string name="pref_aawireless_dongle_confirmation">After toggling dongle mode, you will need to pair the device again. Please wait at least 30 seconds for the setting to be applied.</string>
|
||||
<string name="switch_to_next_phone">Next phone</string>
|
||||
<string name="toggle_standby_on_off">Standby on/off</string>
|
||||
<string name="advanced_settings">Advanced settings</string>
|
||||
<string name="country">Country</string>
|
||||
<string name="developer_mode">Developer mode</string>
|
||||
<string name="double_click">Double click</string>
|
||||
<string name="dpi_dots_per_inch">Screen DPI</string>
|
||||
<string name="factory_reset">Factory reset</string>
|
||||
<string name="long_press_10_seconds">Long press (10 sec.)</string>
|
||||
<string name="long_press_2_seconds">Long press (2 sec.)</string>
|
||||
<string name="no_paired_phones">There are no paired phones</string>
|
||||
<string name="paired_phones">Paired phones</string>
|
||||
<string name="pairing_mode">Pairing mode</string>
|
||||
<string name="pref_aawireless_audio_stutter_fix_high">High</string>
|
||||
<string name="pref_aawireless_audio_stutter_fix_low">Low</string>
|
||||
<string name="pref_aawireless_audio_stutter_fix_summary">Override the audio buffer to fix audio stutter</string>
|
||||
<string name="pref_aawireless_audio_stutter_fix_title">Audio stutter fix</string>
|
||||
<string name="pref_aawireless_audio_stutter_fix_unlimited">Unlimited</string>
|
||||
<string name="pref_aawireless_auto_standby_enabled">Auto standby enabled</string>
|
||||
<string name="pref_aawireless_auto_standby_device">Auto standby device</string>
|
||||
<string name="pref_aawireless_auto_standby_summary">Automatically enable standby mode when the selected device is not connected to the phone. Enable this if the USB port in your car has power when the car is off.</string>
|
||||
<string name="pref_aawireless_auto_video_focus_summary">Automatically open Android Auto when connected, skipping the manual screen prompt. Might not work on all cars.</string>
|
||||
<string name="pref_aawireless_auto_video_focus_title">Auto-start Android Auto</string>
|
||||
<string name="pref_aawireless_developer_mode_summary">Enable for app development</string>
|
||||
<string name="pref_aawireless_disable_media_sink_summary">Allow media playback through a different Bluetooth device</string>
|
||||
<string name="pref_aawireless_disable_media_sink_title">Disable media sink</string>
|
||||
<string name="pref_aawireless_disable_tts_sink_summary">Allow speech instructions to through a different Bluetooth device</string>
|
||||
<string name="pref_aawireless_disable_tts_sink_title">Disable TTS sink</string>
|
||||
<string name="pref_aawireless_dongle_mode_summary">Use the native dongle logic for Android Auto. This may help with bluetooth hands-free connectivity issues. When enabled, manual phone switching is not possible.</string>
|
||||
<string name="pref_aawireless_dongle_mode_title">Dongle mode</string>
|
||||
<string name="pref_aawireless_dpi_summary">Set to 0 to use the car\'s default value</string>
|
||||
<string name="pref_aawireless_passthrough_summary">Pass data directly, without any processing</string>
|
||||
<string name="pref_aawireless_passthrough_title">Passthrough</string>
|
||||
<string name="pref_aawireless_prefer_last">Prefer last connected phone</string>
|
||||
<string name="pref_aawireless_remove_tap_restriction_summary">Allow over 6 taps in succession. May impact GPS accuracy.</string>
|
||||
<string name="pref_aawireless_remove_tap_restriction_title">Remove tap restriction</string>
|
||||
<string name="pref_aawireless_start_fix_summary">Workaround - enable this if the LED is solid blue, but Android Auto is not starting</string>
|
||||
<string name="pref_aawireless_start_fix_title">Start fix</string>
|
||||
<string name="pref_aawireless_vag_crash_fix_summary">Fix crash on VAG Technisat units during song skip/pause. Do not enable on other cars, may cause glitches.</string>
|
||||
<string name="pref_aawireless_vag_crash_fix_title">VAG crash fix</string>
|
||||
<string name="single_click">Single click</string>
|
||||
<string name="switch_to_phone">Switch to %1$s</string>
|
||||
<string name="wifi_channel">Wi-Fi Channel</string>
|
||||
<string name="wifi_frequency_2_4_ghz">2.4 GHz</string>
|
||||
<string name="wifi_frequency_5_ghz">5 GHz</string>
|
||||
<string name="wifi_frequency">Wi-Fi Frequency</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="dongle_mode"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_dongle_mode_summary"
|
||||
android:title="@string/pref_aawireless_dongle_mode_title"
|
||||
app:icon="@drawable/ic_usb_dongle" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="passthrough"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_passthrough_summary"
|
||||
android:title="@string/pref_aawireless_passthrough_title"
|
||||
app:disableDependentsState="true"
|
||||
app:icon="@drawable/ic_arrow_depth" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="off"
|
||||
android:dependency="passthrough"
|
||||
android:entries="@array/aawireless_audio_stutter_fix_names"
|
||||
android:entryValues="@array/aawireless_audio_stutter_fix_values"
|
||||
android:key="audio_stutter_fix"
|
||||
android:summary="@string/pref_aawireless_audio_stutter_fix_summary"
|
||||
android:title="@string/pref_aawireless_audio_stutter_fix_title"
|
||||
app:icon="@drawable/ic_volume_up" />
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue="0"
|
||||
android:dependency="passthrough"
|
||||
android:key="dpi"
|
||||
android:summary="@string/pref_aawireless_dpi_summary"
|
||||
android:title="@string/dpi_dots_per_inch"
|
||||
app:icon="@drawable/ic_font_size" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="passthrough"
|
||||
android:key="disable_media_sink"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_disable_media_sink_summary"
|
||||
android:title="@string/pref_aawireless_disable_media_sink_title"
|
||||
app:icon="@drawable/ic_music_note" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="passthrough"
|
||||
android:key="disable_tts_sink"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_disable_tts_sink_summary"
|
||||
android:title="@string/pref_aawireless_disable_tts_sink_title"
|
||||
app:icon="@drawable/ic_voice" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="passthrough"
|
||||
android:key="remove_tap_restriction"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_remove_tap_restriction_summary"
|
||||
android:title="@string/pref_aawireless_remove_tap_restriction_title"
|
||||
app:icon="@drawable/ic_touch" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="passthrough"
|
||||
android:key="vag_crash_fix"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_vag_crash_fix_summary"
|
||||
android:title="@string/pref_aawireless_vag_crash_fix_title"
|
||||
app:icon="@drawable/ic_extension" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="passthrough"
|
||||
android:key="start_fix"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_start_fix_summary"
|
||||
android:title="@string/pref_aawireless_start_fix_title"
|
||||
app:icon="@drawable/ic_extension" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="passthrough"
|
||||
android:key="developer_mode"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_developer_mode_summary"
|
||||
android:title="@string/developer_mode"
|
||||
app:icon="@drawable/ic_developer_mode" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:dependency="passthrough"
|
||||
android:key="auto_video_focus"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_auto_video_focus_summary"
|
||||
android:title="@string/pref_aawireless_auto_video_focus_title"
|
||||
app:icon="@drawable/ic_focus" />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="auto_standby_enabled"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:summary="@string/pref_aawireless_auto_standby_summary"
|
||||
android:title="@string/pref_aawireless_auto_standby_enabled"
|
||||
app:icon="@drawable/ic_activity_sleep" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue=""
|
||||
android:dependency="auto_standby_enabled"
|
||||
android:entries="@array/empty_array"
|
||||
android:entryValues="@array/empty_array"
|
||||
android:key="auto_standby_device"
|
||||
android:title="@string/pref_aawireless_auto_standby_device"
|
||||
app:icon="@drawable/ic_devices_other"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceScreen
|
||||
android:icon="@drawable/ic_touch"
|
||||
android:key="screen_button_actions"
|
||||
android:persistent="false"
|
||||
android:summary="@string/mi2_prefs_button_actions_summary"
|
||||
android:title="@string/mi2_prefs_button_actions">
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="none"
|
||||
android:entries="@array/aawireless_click_names"
|
||||
android:entryValues="@array/aawireless_click_values"
|
||||
android:icon="@drawable/ic_filter_1"
|
||||
android:key="button_mode_single_click"
|
||||
android:title="@string/single_click"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
android:defaultValue="none"
|
||||
android:entries="@array/aawireless_click_names"
|
||||
android:entryValues="@array/aawireless_click_values"
|
||||
android:icon="@drawable/ic_filter_2"
|
||||
android:key="button_mode_double_click"
|
||||
android:title="@string/double_click"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:icon="@drawable/ic_horizontal_rule"
|
||||
android:key="button_mode_long_press_2s"
|
||||
android:shouldDisableView="false"
|
||||
android:summary="@string/pairing_mode"
|
||||
android:title="@string/long_press_2_seconds" />
|
||||
|
||||
<Preference
|
||||
android:enabled="false"
|
||||
android:icon="@drawable/ic_horizontal_rule"
|
||||
android:key="button_mode_long_press_10s"
|
||||
android:shouldDisableView="false"
|
||||
android:summary="@string/factory_reset"
|
||||
android:title="@string/long_press_10_seconds" />
|
||||
</PreferenceScreen>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<PreferenceScreen
|
||||
android:icon="@drawable/ic_smartphone"
|
||||
android:key="screen_paired_phones"
|
||||
android:persistent="false"
|
||||
android:title="@string/paired_phones">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="prefer_last_connected"
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:title="@string/pref_aawireless_prefer_last"
|
||||
app:icon="@drawable/ic_bluetooth_connected" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:key="paired_phones_header"
|
||||
android:title="@string/paired_phones"
|
||||
app:iconSpaceReserved="false">
|
||||
|
||||
<Preference
|
||||
android:key="no_paired_phones"
|
||||
android:summary="@string/no_paired_phones"
|
||||
app:iconSpaceReserved="false" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@@ -7,11 +7,6 @@
|
||||
android:summary="@string/mi2_prefs_button_actions_summary"
|
||||
android:title="@string/mi2_prefs_button_actions">
|
||||
|
||||
<!-- workaround for missing toolbar -->
|
||||
<PreferenceCategory android:title="@string/mi2_prefs_button_action" />
|
||||
|
||||
public static final String PREF_BUTTON_ACTION_PRESS_DELAY = "button_action_press_count_delay";
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:icon="@drawable/ic_smart_button"
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<EditTextPreference
|
||||
android:defaultValue="US"
|
||||
android:key="country"
|
||||
android:title="@string/country"
|
||||
app:icon="@drawable/ic_language"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceScreen
|
||||
android:icon="@drawable/ic_warning"
|
||||
android:key="pref_screen_advanced_settings"
|
||||
android:persistent="false"
|
||||
android:title="@string/advanced_settings">
|
||||
</PreferenceScreen>
|
||||
</androidx.preference.PreferenceScreen>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<ListPreference
|
||||
android:defaultValue="5"
|
||||
android:entries="@array/wifi_frequency_names"
|
||||
android:entryValues="@array/wifi_frequency_values"
|
||||
android:icon="@drawable/ic_wifi_tethering"
|
||||
android:key="wifi_frequency"
|
||||
android:title="@string/wifi_frequency"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/wifi_channels_2_4_ghz"
|
||||
android:entryValues="@array/wifi_channels_2_4_ghz"
|
||||
android:icon="@drawable/ic_frequency"
|
||||
android:key="wifi_channel_2_4"
|
||||
android:title="@string/wifi_channel"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
|
||||
<ListPreference
|
||||
android:entries="@array/wifi_channels_5_ghz"
|
||||
android:entryValues="@array/wifi_channels_5_ghz"
|
||||
android:icon="@drawable/ic_frequency"
|
||||
android:key="wifi_channel_5"
|
||||
android:title="@string/wifi_channel"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</androidx.preference.PreferenceScreen>
|
||||
Reference in New Issue
Block a user