1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-26 11:56:48 +01:00

Fossil Hybrid: file handle can be passed to service as string

This commit is contained in:
Daniel Dakhno 2021-01-30 21:10:25 +01:00
parent 251aee8c74
commit ec77345632
8 changed files with 175 additions and 47 deletions

View File

@ -16,6 +16,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */ along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid; package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
import android.app.AlertDialog;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -23,6 +24,7 @@ import android.content.IntentFilter;
import android.os.Bundle; import android.os.Bundle;
import android.view.View; import android.view.View;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ExpandableListView; import android.widget.ExpandableListView;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.Switch; import android.widget.Switch;
@ -31,6 +33,9 @@ import android.widget.Toast;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.nio.file.attribute.FileTime; import java.nio.file.attribute.FileTime;
@ -39,12 +44,16 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class FileManagementActivity extends AbstractGBActivity implements View.OnClickListener { public class FileManagementActivity extends AbstractGBActivity implements View.OnClickListener {
private final int REQUEST_CODE_PICK_UPLOAD_FILE = 0; private final int REQUEST_CODE_PICK_UPLOAD_FILE = 0;
private Spinner fileTypesSpinner; private Spinner fileTypesSpinner;
private Switch encryptedFile; private Switch encryptedFile;
private boolean generateFileHeader = false;
private boolean warningDisplayed = false;
BroadcastReceiver fileResultReceiver = new BroadcastReceiver() { BroadcastReceiver fileResultReceiver = new BroadcastReceiver() {
@Override @Override
@ -100,6 +109,15 @@ public class FileManagementActivity extends AbstractGBActivity implements View.O
findViewById(R.id.qhybrid_button_download_file).setOnClickListener(this); findViewById(R.id.qhybrid_button_download_file).setOnClickListener(this);
findViewById(R.id.qhybrid_button_upload_file).setOnClickListener(this); findViewById(R.id.qhybrid_button_upload_file).setOnClickListener(this);
((Switch) findViewById(R.id.sqhybrid_switch_generate_file_header)).setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
generateFileHeader = isChecked;
fileTypesSpinner.setClickable(isChecked);
fileTypesSpinner.setAlpha(isChecked ? 1f : 0.2f);
}
});
} }
@Override @Override
@ -108,13 +126,41 @@ public class FileManagementActivity extends AbstractGBActivity implements View.O
if(requestCode != REQUEST_CODE_PICK_UPLOAD_FILE) return; if(requestCode != REQUEST_CODE_PICK_UPLOAD_FILE) return;
if(resultCode != RESULT_OK) return; if(resultCode != RESULT_OK) return;
Intent callIntent = new Intent(QHybridSupport.QHYBRID_COMMAND_UPLOAD_FILE); String path = data.getData().getPath();
callIntent.putExtra("EXTRA_HANDLE", (FileHandle) fileTypesSpinner.getSelectedItem());
callIntent.putExtra("EXTRA_ENCRYPTED", encryptedFile.isChecked());
callIntent.putExtra("EXTRA_PATH", data.getData().getPath());
// callIntent.setData(data.getData());
LocalBroadcastManager.getInstance(this).sendBroadcast(callIntent); try {
if(!warningDisplayed) {
FileInputStream fis = new FileInputStream(path);
short fileHandle = (short) (fis.read() | (fis.read() << 8));
fis.close();
boolean handleFound = FileHandle.fromHandle(fileHandle) != null;
if (handleFound == generateFileHeader) {
warningDisplayed = true;
String text = "File seems to contain file handle. Are you sure you want to generate a potentially already existing header?";
if(!handleFound) text = "File does not start with a known handle. Are you sure the header is already generated?";
text += " Repeat to continue anyway.";
new AlertDialog.Builder(this)
.setTitle("warning")
.setMessage(text)
.setPositiveButton("ok", null)
.show();
return;
}
}
Intent callIntent = new Intent(QHybridSupport.QHYBRID_COMMAND_UPLOAD_FILE);
callIntent.putExtra("EXTRA_HANDLE", (FileHandle) fileTypesSpinner.getSelectedItem());
callIntent.putExtra("EXTRA_ENCRYPTED", encryptedFile.isChecked());
callIntent.putExtra("EXTRA_GENERATE_FILE_HEADER", generateFileHeader);
callIntent.putExtra("EXTRA_PATH", data.getData().getPath());
// callIntent.setData(data.getData());
LocalBroadcastManager.getInstance(this).sendBroadcast(callIntent);
} catch (IOException e) {
e.printStackTrace();
GB.toast("cannot open file", Toast.LENGTH_LONG, GB.ERROR);
}
} }
@Override @Override

View File

@ -283,15 +283,7 @@ public class QHybridSupport extends QHybridBaseSupport {
break; break;
} }
case QHYBRID_COMMAND_UPLOAD_FILE:{ case QHYBRID_COMMAND_UPLOAD_FILE:{
Object handleObject = intent.getSerializableExtra("EXTRA_HANDLE"); handleFileUploadIntent(intent);
if(handleObject == null)return;
if(handleObject instanceof String){
handleObject = FileHandle.fromName((String)handleObject);
}
if(!(handleObject instanceof FileHandle)) return;
FileHandle handle = (FileHandle) handleObject;
String filePath = intent.getStringExtra("EXTRA_PATH");
watchAdapter.uploadFile(handle, filePath, intent.getBooleanExtra("EXTRA_ENCRYPTED", false));
break; break;
} }
} }
@ -369,15 +361,7 @@ public class QHybridSupport extends QHybridBaseSupport {
break; break;
} }
case QHYBRID_COMMAND_UPLOAD_FILE:{ case QHYBRID_COMMAND_UPLOAD_FILE:{
Object handleObject = intent.getSerializableExtra("EXTRA_HANDLE"); handleFileUploadIntent(intent);
if(handleObject == null)return;
if(handleObject instanceof String){
handleObject = FileHandle.fromName((String)handleObject);
}
if(!(handleObject instanceof FileHandle)) return;
FileHandle handle = (FileHandle) handleObject;
String filePath = intent.getStringExtra("EXTRA_PATH");
watchAdapter.uploadFile(handle, filePath, intent.getBooleanExtra("EXTRA_ENCRYPTED", false));
break; break;
} }
} }
@ -386,6 +370,23 @@ public class QHybridSupport extends QHybridBaseSupport {
GBApplication.getContext().registerReceiver(globalCommandReceiver, globalFilter); GBApplication.getContext().registerReceiver(globalCommandReceiver, globalFilter);
} }
private void handleFileUploadIntent(Intent intent){
boolean generateHeader = intent.getBooleanExtra("EXTRA_GENERATE_FILE_HEADER", false);
String filePath = intent.getStringExtra("EXTRA_PATH");
if(!generateHeader){
watchAdapter.uploadFileIncludesHeader(filePath);
return;
}
Object handleObject = intent.getSerializableExtra("EXTRA_HANDLE");
if(handleObject == null)return;
if(handleObject instanceof String){
handleObject = FileHandle.fromName((String)handleObject);
}
if(!(handleObject instanceof FileHandle)) return;
FileHandle handle = (FileHandle) handleObject;
watchAdapter.uploadFileGenerateHeader(handle, filePath, intent.getBooleanExtra("EXTRA_ENCRYPTED", false));
}
@Override @Override
public void onSetCallState(CallSpec callSpec) { public void onSetCallState(CallSpec callSpec) {
super.onSetCallState(callSpec); super.onSetCallState(callSpec);

View File

@ -145,7 +145,10 @@ public abstract class WatchAdapter {
public void downloadFile(FileHandle handle, boolean fileIsEncrypted) { public void downloadFile(FileHandle handle, boolean fileIsEncrypted) {
} }
public void uploadFile(FileHandle handle, String filePath, boolean fileIsEncrypted) { public void uploadFileGenerateHeader(FileHandle handle, String filePath, boolean fileIsEncrypted) {
}
public void uploadFileIncludesHeader(String filePath){
} }
public void factoryReset() { public void factoryReset() {

View File

@ -49,6 +49,7 @@ import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -71,6 +72,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.Weather; import nodomain.freeyourgadget.gadgetbridge.model.Weather;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec; import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.Transaction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle;
@ -83,8 +85,11 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fos
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FileGetRawRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FileGetRawRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FileLookupRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FileLookupRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRawRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRawRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.file.FilePutRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayCallNotificationRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayCallNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayTextNotificationRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.notification.PlayTextNotificationRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.application.ApplicationInformation;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.application.ApplicationsListRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.async.ConfirmAppStatusRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.async.ConfirmAppStatusRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.VerifyPrivateKeyRequest; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.authentication.VerifyPrivateKeyRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.buttons.ButtonConfiguration; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.buttons.ButtonConfiguration;
@ -141,6 +146,8 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
HashMap<String, Bitmap> appIconCache = new HashMap<>(); HashMap<String, Bitmap> appIconCache = new HashMap<>();
String lastPostedApp = null; String lastPostedApp = null;
List<ApplicationInformation> installedApplications;
enum CONNECTION_MODE { enum CONNECTION_MODE {
NOT_INITIALIZED, NOT_INITIALIZED,
AUTHENTICATED, AUTHENTICATED,
@ -157,6 +164,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
queueWrite(new RequestMtuRequest(512)); queueWrite(new RequestMtuRequest(512));
} }
listApplications();
getDeviceInfos(); getDeviceInfos();
} }
@ -173,6 +181,15 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
negotiateSymmetricKey(); negotiateSymmetricKey();
} }
private void listApplications(){
queueWrite(new ApplicationsListRequest(this) {
@Override
public void handleApplicationsList(List<ApplicationInformation> applications) {
installedApplications = applications;
}
});
}
private void initializeAfterAuthentication(boolean authenticated) { private void initializeAfterAuthentication(boolean authenticated) {
queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZING)); queueWrite(new SetDeviceStateRequest(GBDevice.State.INITIALIZING));
@ -186,10 +203,9 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
setVibrationStrength(); setVibrationStrength();
syncSettings(); syncSettings();
setTime(); setTime();
overwriteButtons(null);
} }
overwriteButtons(null);
loadBackground(); loadBackground();
loadWidgets(); loadWidgets();
// renderWidgets(); // renderWidgets();
@ -568,7 +584,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
} }
@Override @Override
public void uploadFile(FileHandle handle, String filePath, boolean fileIsEncrypted) { public void uploadFileGenerateHeader(FileHandle handle, String filePath, boolean fileIsEncrypted) {
final Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_UPLOADED_FILE); final Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_UPLOADED_FILE);
byte[] fileData; byte[] fileData;
@ -584,7 +600,7 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
return; return;
} }
queueWrite(new FilePutRawRequest(handle, fileData, this) { queueWrite(new FilePutRequest(handle, fileData, this) {
@Override @Override
public void onFilePut(boolean success) { public void onFilePut(boolean success) {
resultIntent.putExtra("EXTRA_SUCCESS", success); resultIntent.putExtra("EXTRA_SUCCESS", success);
@ -593,6 +609,38 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
}); });
} }
@Override
public void uploadFileIncludesHeader(String filePath) {
final Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_UPLOADED_FILE);
byte[] fileData;
try {
FileInputStream fis = new FileInputStream(filePath);
fileData = new byte[fis.available()];
fis.read(fileData);
fis.close();
short handleBytes = (short)(fileData[0] & 0xFF | ((fileData[1] & 0xFF) << 8));
FileHandle handle = FileHandle.fromHandle(handleBytes);
if(handle == null){
throw new RuntimeException("unknown handle");
}
queueWrite(new FilePutRawRequest(handle, fileData, this) {
@Override
public void onFilePut(boolean success) {
resultIntent.putExtra("EXTRA_SUCCESS", success);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(resultIntent);
}
});
} catch (Exception e) {
e.printStackTrace();
resultIntent.putExtra("EXTRA_SUCCESS", false);
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(resultIntent);
}
}
@Override @Override
public void downloadFile(final FileHandle handle, boolean fileIsEncrypted) { public void downloadFile(final FileHandle handle, boolean fileIsEncrypted) {
if (fileIsEncrypted) { if (fileIsEncrypted) {
@ -1081,10 +1129,6 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
@Override @Override
public void overwriteButtons(String jsonConfigString) { public void overwriteButtons(String jsonConfigString) {
if (connectionMode == CONNECTION_MODE.NOT_AUTHENTICATED) {
GB.toast("not available in unauthenticated mode", Toast.LENGTH_LONG, GB.ERROR);
return;
}
try { try {
JSONArray jsonArray = new JSONArray( JSONArray jsonArray = new JSONArray(
GBApplication.getPrefs().getString(HRConfigActivity.CONFIG_KEY_Q_ACTIONS, "[]") GBApplication.getPrefs().getString(HRConfigActivity.CONFIG_KEY_Q_ACTIONS, "[]")
@ -1104,24 +1148,31 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
if (version.compareTo(new Version("1.0.2.19")) == -1) if (version.compareTo(new Version("1.0.2.19")) == -1)
singlePressEvent = "single_click"; singlePressEvent = "single_click";
} }
ArrayList<ButtonConfiguration> configs = new ArrayList<>(5);
configs.add(new ButtonConfiguration("top_" + singlePressEvent, prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_1_FUNCTION_SHORT, "weatherApp")));
configs.add(new ButtonConfiguration("top_hold", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_1_FUNCTION_LONG, "weatherApp")));
// configs.add(new ButtonConfiguration("top_double_click", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_1_FUNCTION_DOUBLE, "weatherApp")));
configs.add(new ButtonConfiguration("middle_" + singlePressEvent, prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_2_FUNCTION_SHORT, "commuteApp")));
// configs.add(new ButtonConfiguration("middle_hold", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_2_FUNCTION_LONG, "commuteApp")));
// configs.add(new ButtonConfiguration("middle_double_click", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_2_FUNCTION_DOUBLE, "commuteApp")));
configs.add(new ButtonConfiguration("bottom_" + singlePressEvent, prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_3_FUNCTION_SHORT, "musicApp")));
configs.add(new ButtonConfiguration("bottom_hold", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_3_FUNCTION_LONG, "musicApp")));
// configs.add(new ButtonConfiguration("bottom_double_click", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_3_FUNCTION_DOUBLE, "musicApp")));
ButtonConfiguration[] buttonConfigurations = new ButtonConfiguration[]{ // filter out all apps not installed on watch
new ButtonConfiguration("top_" + singlePressEvent, prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_1_FUNCTION_SHORT, "weatherApp")), outerLoop: for (ButtonConfiguration config : configs){
new ButtonConfiguration("top_hold", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_1_FUNCTION_LONG, "weatherApp")), for(ApplicationInformation installedApp : installedApplications){
new ButtonConfiguration("top_double_click", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_1_FUNCTION_DOUBLE, "weatherApp")), if(installedApp.getAppName().equals(config.getAction())){
continue outerLoop;
}
}
configs.remove(config);
}
new ButtonConfiguration("middle_" + singlePressEvent, prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_2_FUNCTION_SHORT, "commuteApp")),
// new ButtonConfiguration("middle_hold", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_2_FUNCTION_LONG, "commuteApp")),
new ButtonConfiguration("middle_double_click", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_2_FUNCTION_DOUBLE, "commuteApp")),
new ButtonConfiguration("bottom_" + singlePressEvent, prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_3_FUNCTION_SHORT, "musicApp")),
new ButtonConfiguration("bottom_hold", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_3_FUNCTION_LONG, "musicApp")),
new ButtonConfiguration("bottom_double_click", prefs.getString(DeviceSettingsPreferenceConst.PREF_BUTTON_3_FUNCTION_DOUBLE, "musicApp")),
};
queueWrite(new ButtonConfigurationPutRequest( queueWrite(new ButtonConfigurationPutRequest(
menuItems, menuItems,
buttonConfigurations, configs.toArray(new ButtonConfiguration[0]),
this this
)); ));
} catch (JSONException e) { } catch (JSONException e) {

View File

@ -57,6 +57,15 @@ public enum FileHandle {
return null; return null;
} }
public static FileHandle fromHandle(short handleBytes){
for(FileHandle handle : FileHandle.values()){
if(handle.getHandle() == handleBytes){
return handle;
}
}
return null;
}
public short getHandle(){ public short getHandle(){
return (short)((handle << 8) | (subHandle)); return (short)((handle << 8) | (subHandle));
} }

View File

@ -28,6 +28,10 @@ public class ButtonConfiguration {
this.action = action; this.action = action;
} }
public String getAction() {
return action;
}
public JSONObject toJsonObject(){ public JSONObject toJsonObject(){
try { try {
return new JSONObject() return new JSONObject()

View File

@ -10,7 +10,9 @@
<Spinner <Spinner
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/qhybrid_file_types" /> android:id="@+id/qhybrid_file_types"
android:alpha="0.2"
android:clickable="false"/>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -24,6 +26,12 @@
android:text="encrypted file" android:text="encrypted file"
android:id="@+id/qhybrid_switch_encrypted_file" /> android:id="@+id/qhybrid_switch_encrypted_file" />
<Switch
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="generate file header"
android:id="@+id/sqhybrid_switch_generate_file_header" />
<Button <Button
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@ -16,6 +16,7 @@
android:key="button_1_function_long" android:key="button_1_function_long"
android:summary="%s" android:summary="%s"
android:title="@string/pref_title_upper_button_function_long" /> android:title="@string/pref_title_upper_button_function_long" />
<!-- supported FW does not support double click
<ListPreference <ListPreference
android:defaultValue="weatherApp" android:defaultValue="weatherApp"
android:entries="@array/pref_hybridhr_buttonfunctions" android:entries="@array/pref_hybridhr_buttonfunctions"
@ -23,6 +24,7 @@
android:key="button_1_function_double" android:key="button_1_function_double"
android:summary="%s" android:summary="%s"
android:title="@string/pref_title_upper_button_function_double" /> android:title="@string/pref_title_upper_button_function_double" />
-->
<ListPreference <ListPreference
android:defaultValue="commuteApp" android:defaultValue="commuteApp"
@ -31,6 +33,7 @@
android:key="button_2_function_short" android:key="button_2_function_short"
android:summary="%s" android:summary="%s"
android:title="@string/pref_title_middle_button_function_short" /> android:title="@string/pref_title_middle_button_function_short" />
<!-- supported FW does not support double click
<ListPreference <ListPreference
android:defaultValue="commuteApp" android:defaultValue="commuteApp"
android:entries="@array/pref_hybridhr_buttonfunctions" android:entries="@array/pref_hybridhr_buttonfunctions"
@ -38,6 +41,7 @@
android:key="button_2_function_double" android:key="button_2_function_double"
android:summary="%s" android:summary="%s"
android:title="@string/pref_title_middle_button_function_double" /> android:title="@string/pref_title_middle_button_function_double" />
-->
<ListPreference <ListPreference
android:defaultValue="musicApp" android:defaultValue="musicApp"
@ -53,6 +57,7 @@
android:key="button_3_function_long" android:key="button_3_function_long"
android:summary="%s" android:summary="%s"
android:title="@string/pref_title_lower_button_function_long" /> android:title="@string/pref_title_lower_button_function_long" />
<!-- supported FW does not support double click
<ListPreference <ListPreference
android:defaultValue="musicApp" android:defaultValue="musicApp"
android:entries="@array/pref_hybridhr_buttonfunctions" android:entries="@array/pref_hybridhr_buttonfunctions"
@ -60,6 +65,7 @@
android:key="button_3_function_double" android:key="button_3_function_double"
android:summary="%s" android:summary="%s"
android:title="@string/pref_title_lower_button_function_double" /> android:title="@string/pref_title_lower_button_function_double" />
-->
<SwitchPreference <SwitchPreference
android:defaultValue="false" android:defaultValue="false"