diff --git a/.gitignore b/.gitignore
index 1a1cda953..f2490d24e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,9 @@ local.properties
build/
gen/
+#app bundle files
+*.aab
+
# Intellij files (Android Studio)
*.iml
diff --git a/.travis.yml b/.travis.yml
index 023f6964e..e71115664 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -30,6 +30,6 @@ notifications:
email: false
script:
- ./gradlew wear:lintRelease
-- ./gradlew assembleLatestRelease
-- ./gradlew lintLatestRelease
-- ./gradlew test
+- ./gradlew app:lintLatestRelease
+- ./gradlew app:assembleLatestRelease
+- ./gradlew app:test
diff --git a/README.md b/README.md
index bbded4ba6..a0da8d8a7 100644
--- a/README.md
+++ b/README.md
@@ -22,11 +22,9 @@ Track your sport activities with RunnerUp using the GPS in your Android phone.
## Release
-* [Play Store](https://play.google.com/store/apps/details?id=org.runnerup).
-* [GitHub](https://github.com/jonasoreland/runnerup/releases). (RunnerUp 2.x versions including beta and release candidates.)
-* [F-Droid](https://f-droid.org/packages/org.runnerup.free/). This version does not contain some features due to licensing, see the F-Droid description.
-
-Join the beta program in Play for release candidates or monitor releases on GitHub.
+* [Play Store](https://play.google.com/store/apps/details?id=org.runnerup) Join [beta group](https://play.google.com/apps/testing/org.runnerup) for early access.
+* [GitHub](https://github.com/jonasoreland/runnerup/releases) All releases, including alpha releases.
+* [F-Droid](https://f-droid.org/packages/org.runnerup.free/) This version does not contain some features due to licensing, see the F-Droid description.
The current 2.x release support Android 4.0 and later. The Play release also supports Android 2.2, 2.3, but due to lack of test devices, RunnerUp cannot support Android 2.x. The "Froyo" version do not include graphs, maps and elevation GeoId correction.
diff --git a/app/AndroidManifest.xml b/app/AndroidManifest.xml
index b5e991882..1485dd590 100644
--- a/app/AndroidManifest.xml
+++ b/app/AndroidManifest.xml
@@ -25,7 +25,6 @@
-
diff --git a/app/assets/changes.html b/app/assets/changes.html
index 087e18c94..6364c3bf5 100644
--- a/app/assets/changes.html
+++ b/app/assets/changes.html
@@ -5,13 +5,29 @@
What's new
+
v2.1.0.0
+
+
+
Minor version number changed to 2.1 to prepare for Play release, previous production is 2.0.2.1
+
#946 Play console feedback
+
+
Translations update: Czech cue, Romanian, Indonesian
+
Accessibility: Increase size of touch targets for most targets with smaller areas
+
Accessibility: Set content descriptions, for visually disabled users
+
Revert from R8 to Proguard to avoid some 4.3 crashes, improved debugging of crashes
+
Decrease app size
+
Fix a few rare crashes
+
See Git log for further details
+
+
+
v2.0.6.4
#938 Add time info to the exported filename
#939 #937 Chinese support
#936 Disable Dropbox provider by default
-
#934 Audio cues for r
+
#934 Audio cues for ro
v2.0.6.3
diff --git a/app/build.gradle b/app/build.gradle
index eab54d28b..2c7ace29e 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -26,7 +26,7 @@ android {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src/main']
- if (rootProject.ext.allowNonFree) {
+ if (rootProject.ext.enableWear) {
java.srcDirs += ['src/play']
} else {
java.srcDirs += ['src/free']
@@ -48,7 +48,7 @@ android {
compileSdkVersion rootProject.ext.compileSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionName rootProject.ext.versionName
- versionCode 14000000 + rootProject.ext.versionCode
+ versionCode rootProject.ext.latestBaseVersionCode + rootProject.ext.versionCode
}
}
@@ -69,7 +69,7 @@ android {
applicationId = rootProject.ext.applicationId
vectorDrawables.useSupportLibrary = true
//By default all AppCompat translations are included, saves 350KB
- resConfigs "ar", "bs", "cs", "ca", "de", "en", "es", "fa", "fi", "fr", "hu", "id", "it", "ja", "lt", "nb", "nl", "pl", "pt", "ru", "sv", "tr", "zh"
+ resConfigs "ar", "bs", "cs", "ca", "de", "en", "es", "fa", "fi", "fr", "hu", "id", "in", "it", "ja", "lt", "nb", "nl", "pl", "pt", "ro", "ru", "sv", "tr", "zh"
}
signingConfigs {
@@ -117,19 +117,21 @@ repositories {
dependencies {
implementation project(':common')
implementation project(':hrdevice')
- if (rootProject.ext.allowNonFree) {
+ if (rootProject.ext.enableWear) {
latestWearApp project(':wear')
}
//noinspection GradleCompatible
latestImplementation "com.android.support:design:${rootProject.ext.supportLibrary}"
latestImplementation "com.android.support:cardview-v7:${rootProject.ext.supportLibrary}"
- //noinspection GradleDependency
- latestImplementation "com.google.android.gms:play-services-wearable:${rootProject.ext.googlePlayServicesVersion}"
+ if (rootProject.ext.enableWear) {
+ //noinspection GradleDependency
+ latestImplementation "com.google.android.gms:play-services-wearable:${rootProject.ext.googlePlayServicesVersion}"
+ }
latestImplementation 'com.getpebble:pebblekit:4.0.1'
// MapBox uses telemetry, without Play there may be exceptions from mapbox: just ignore
//latestImplementation "com.google.android.gms:play-services-location:${rootProject.ext.googlePlayServicesVersion}"
- latestImplementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:8.2.1'
+ latestImplementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:8.2.2'
latestImplementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v8:0.7.0'
latestImplementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-scalebar-v8:0.2.0'
latestImplementation 'com.jjoe64:graphview:4.2.2'
@@ -208,8 +210,8 @@ android.applicationVariants.all {
//Based on an example from https://developer.android.com/studio/build/configure-apk-splits.html
//Most comments from there removed
-// Map for the version code that gives each ABI a value.
-ext.abiCodes = ['arm64-v8a': 1, 'armeabi':2, 'armeabi-v7a':3, 'mips':4, 'mips64':5, 'x86':6, 'x86_64':7]
+// Map for the version code that gives each ABI a value (generic has lower value)
+ext.abiCodes = ['arm64-v8a': 8, 'armeabi':2, 'armeabi-v7a':3, 'mips':4, 'mips64':5, 'x86':6, 'x86_64':7]
import com.android.build.OutputFile
diff --git a/app/lint-baseline.xml b/app/lint-baseline.xml
index 01fd76364..0f350f63a 100644
--- a/app/lint-baseline.xml
+++ b/app/lint-baseline.xml
@@ -1,11 +1,59 @@
-
+
+ id="UnusedAttribute"
+ message="Attribute `importantForAccessibility` is only used in API level 16 and higher (current min is 15)"
+ errorLine1=" android:importantForAccessibility="no""
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ file="res\layout\bottom_tab_indicator.xml"
+ line="4"
+ column="5"/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -68,6 +72,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/account_upload_button"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:text="@string/Disconnect" />
+ style="@style/ButtonText"
+ android:id="@+id/account_download_button"
+ android:background="@drawable/btn_blue"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="false"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ android:text="@string/Download"
+ android:layout_above="@+id/ok_account_button" />
+ android:id="@+id/ok_account_button"
+ style="@style/ButtonText"
+ android:background="@drawable/btn_green"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ android:text="@string/OK" />
\ No newline at end of file
diff --git a/app/res/layout/account_row.xml b/app/res/layout/account_row.xml
index 7732c9043..f8f25a830 100644
--- a/app/res/layout/account_row.xml
+++ b/app/res/layout/account_row.xml
@@ -66,7 +66,9 @@
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
- android:layout_weight="1" />
+ android:layout_weight="1"
+ android:minWidth="48dp"
+ android:minHeight="48dp" />
diff --git a/app/res/layout/bottom_tab_indicator.xml b/app/res/layout/bottom_tab_indicator.xml
index 310105866..e32f076e6 100644
--- a/app/res/layout/bottom_tab_indicator.xml
+++ b/app/res/layout/bottom_tab_indicator.xml
@@ -1,8 +1,9 @@
diff --git a/app/res/layout/heartratezonerow.xml b/app/res/layout/heartratezonerow.xml
index a86ba8b07..31ad4d7e7 100644
--- a/app/res/layout/heartratezonerow.xml
+++ b/app/res/layout/heartratezonerow.xml
@@ -35,6 +35,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:minHeight="48dp"
+ android:minWidth="48dp"
android:inputType="number"
tools:ignore="labelFor,AutoFill" />
@@ -48,6 +50,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:minHeight="48dp"
+ android:minWidth="48dp"
android:inputType="number"
tools:ignore="labelFor,AutoFill" />
diff --git a/app/res/layout/heartratezones.xml b/app/res/layout/heartratezones.xml
index a387f9f7f..eb2280a05 100644
--- a/app/res/layout/heartratezones.xml
+++ b/app/res/layout/heartratezones.xml
@@ -25,6 +25,8 @@
android:id="@+id/hrz_age"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:text="@string/Age"
app:type="numberpicker"
app:digits="3"
@@ -37,6 +39,8 @@
android:id="@+id/hrz_sex"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:entries="@array/sexes"
android:prompt="@string/Sex"
android:text="@string/Sex"
@@ -48,6 +52,8 @@
android:id="@+id/hrz_mhr"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:text="@string/Maximum_heart_rate_MHR"
app:type="numberpicker"
app:digits="3"
diff --git a/app/res/layout/hr_settings.xml b/app/res/layout/hr_settings.xml
index 0e462d5ce..1184d3d55 100644
--- a/app/res/layout/hr_settings.xml
+++ b/app/res/layout/hr_settings.xml
@@ -95,6 +95,7 @@
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ android:spinnerMode="dropdown" />
@@ -55,19 +57,21 @@
android:id="@android:id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_alignParentTop="true"/>
+ android:layout_alignParentTop="true"
+ android:minWidth="48dp"
+ android:minHeight="48dp" />
+ android:layout_below="@android:id/tabs" >
-
+
-
+
-
+
+ tools:ignore="ContentDescription" />
diff --git a/app/res/layout/start_interval.xml b/app/res/layout/start_interval.xml
index ab4e936df..813e7ab47 100644
--- a/app/res/layout/start_interval.xml
+++ b/app/res/layout/start_interval.xml
@@ -120,6 +120,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:checked="true"
android:enabled="false"
android:text="@string/warm_up" />
@@ -128,6 +130,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:checked="true"
android:enabled="false"
android:text="@string/cool_down" />
diff --git a/app/res/layout/step_button.xml b/app/res/layout/step_button.xml
index df1af1997..792224b26 100644
--- a/app/res/layout/step_button.xml
+++ b/app/res/layout/step_button.xml
@@ -21,6 +21,8 @@
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:background="@drawable/title_spinner"
android:clickable="true"
android:focusable="true"
diff --git a/app/res/layout/step_dialog.xml b/app/res/layout/step_dialog.xml
index d6659f399..8054cf588 100644
--- a/app/res/layout/step_dialog.xml
+++ b/app/res/layout/step_dialog.xml
@@ -16,14 +16,16 @@
~ along with this program. If not, see .
-->
+ xmlns:runnerup="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
+ android:orientation="vertical"
+ android:paddingLeft="16dp"
+ android:paddingTop="@dimen/dialog_padding_vert"
+ android:paddingRight="16dp"
+ android:paddingBottom="@dimen/dialog_padding_vert">
@@ -64,6 +67,7 @@
android:layout_height="wrap_content" >
\ No newline at end of file
diff --git a/app/res/values/array.xml b/app/res/values/array.xml
index b485a3135..e9a559e33 100644
--- a/app/res/values/array.xml
+++ b/app/res/values/array.xml
@@ -42,6 +42,7 @@
العَرَبِيَّةBahasa IndonesiaCatalà
+ ČeštinaDeutschEspañolزبان فارسی
@@ -65,8 +66,9 @@
enar
- id
+ inca
+ csdeesfa
diff --git a/app/res/xml/settings.xml b/app/res/xml/settings.xml
index a417fa9c0..4d4409a85 100644
--- a/app/res/xml/settings.xml
+++ b/app/res/xml/settings.xml
@@ -318,6 +318,8 @@
android:inputType="number"
android:defaultValue="20"
android:key="@string/pref_target_pace_moving_average_seconds"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:persistent="true"
android:title="@string/Target_pace_moving_average_seconds" />
@@ -325,6 +327,8 @@
android:inputType="number"
android:defaultValue="30"
android:key="@string/pref_target_pace_grace_seconds"
+ android:minWidth="48dp"
+ android:minHeight="48dp"
android:persistent="true"
android:title="@string/Target_pace_grace_seconds" />
diff --git a/app/src/main/org/runnerup/export/SyncManager.java b/app/src/main/org/runnerup/export/SyncManager.java
index 27cdc3221..3eb53eda2 100644
--- a/app/src/main/org/runnerup/export/SyncManager.java
+++ b/app/src/main/org/runnerup/export/SyncManager.java
@@ -394,7 +394,11 @@ public void onCheckedChanged(CompoundButton buttonView,
}
if (AuthMethod.USER_PASS_URL.equals(authMethod)) {
rowUrl.setVisibility(View.VISIBLE);
- urlInput.setText(authConfig.optString(DB.ACCOUNT.URL));
+ String url = authConfig.optString(DB.ACCOUNT.URL);
+ if (url == null || url.isEmpty()) {
+ url = sync.getPublicUrl();
+ }
+ urlInput.setText(url);
} else {
rowUrl.setVisibility(View.GONE);
}
diff --git a/app/src/main/org/runnerup/export/WebDavSynchronizer.java b/app/src/main/org/runnerup/export/WebDavSynchronizer.java
index a7651e3ec..baa20db36 100644
--- a/app/src/main/org/runnerup/export/WebDavSynchronizer.java
+++ b/app/src/main/org/runnerup/export/WebDavSynchronizer.java
@@ -48,12 +48,11 @@
public class WebDavSynchronizer extends DefaultSynchronizer {
- public static final String NAME = "WebDav";
+ public static final String NAME = "WebDAV";
private long id = 0;
private PathSimplifier simplifier;
- private FileFormats format;
private String username;
private String password;
private String url;
@@ -80,6 +79,11 @@ public String getName() {
@Override
public String getPublicUrl() {
+ if (url == null || url.isEmpty()) {
+ // Some default to help formatting
+ // TODO Separate URL for upload and access
+ return "https://site.com/remote.php/dav/files/useremail/runnerup";
+ }
return url;
}
diff --git a/app/src/main/org/runnerup/export/oauth2client/OAuth2Activity.java b/app/src/main/org/runnerup/export/oauth2client/OAuth2Activity.java
index 62b21fa86..ed8ad000a 100644
--- a/app/src/main/org/runnerup/export/oauth2client/OAuth2Activity.java
+++ b/app/src/main/org/runnerup/export/oauth2client/OAuth2Activity.java
@@ -100,7 +100,14 @@ public void onCreate(Bundle savedInstanceState) {
mSpinner.requestWindowFeature(Window.FEATURE_NO_TITLE);
mSpinner.setMessage(getString(R.string.Loading));
- final WebView wv = new WebView(this);
+ // https://stackoverflow.com/questions/41025200/android-view-inflateexception-error-inflating-class-android-webkit-webview/58131421#58131421
+ WebView wvt;
+ try {
+ wvt = new WebView(this);
+ } catch (Exception e) {
+ wvt = new WebView(getApplicationContext());
+ }
+ final WebView wv = wvt;
wv.setVerticalScrollBarEnabled(false);
wv.setHorizontalScrollBarEnabled(false);
wv.getSettings().setJavaScriptEnabled(true);
@@ -145,7 +152,6 @@ public void onPageStarted(WebView view, String url, Bitmap favicon) {
mSpinner.show();
}
-
// TODO: Fix "WrongThread"
@SuppressLint({"StaticFieldLeak", "WrongThread"})
@Override
diff --git a/app/src/main/org/runnerup/util/FileNameHelper.java b/app/src/main/org/runnerup/util/FileNameHelper.java
index 362c61f61..dbefa5481 100644
--- a/app/src/main/org/runnerup/util/FileNameHelper.java
+++ b/app/src/main/org/runnerup/util/FileNameHelper.java
@@ -42,10 +42,10 @@ public static String getExportFileName(long activityStartTime, String activityTy
}
/**
- * Generate filename including the model name, to limit sorting in services like DropBox/WebDav
+ * Generate filename including the model name, to limit sorting in services like DropBox/WebDAV
* @param activityStartTime activity start time in unix timestamp
* @param activityType activity type
- * @return the generated filename for DropBox/WebDav
+ * @return the generated filename for DropBox/WebDAV
*/
public static String getExportFileNameWithModel(long activityStartTime, String activityType) {
return String.format(Locale.getDefault(),
diff --git a/app/src/main/org/runnerup/view/AccountActivity.java b/app/src/main/org/runnerup/view/AccountActivity.java
index 9628b42d1..8f988b632 100644
--- a/app/src/main/org/runnerup/view/AccountActivity.java
+++ b/app/src/main/org/runnerup/view/AccountActivity.java
@@ -33,6 +33,7 @@
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
+import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
@@ -202,6 +203,8 @@ private void fillData() {
cb.setTag(DB.ACCOUNT.FLAG_UPLOAD);
cb.setChecked(Bitfield.test(flags, DB.ACCOUNT.FLAG_UPLOAD));
cb.setOnCheckedChangeListener(sendCBChecked);
+ cb.setMinimumHeight(48);
+ cb.setMinimumWidth(48);
addRow(getResources().getString(R.string.Automatic_upload), cb);
} else {
Button btn = (Button) findViewById(R.id.account_upload_button);
@@ -216,6 +219,8 @@ private void fillData() {
cb.setChecked(format.contains(f));
cb.setTag(f);
cb.setOnCheckedChangeListener(sendCBChecked);
+ cb.setMinimumHeight(48);
+ cb.setMinimumWidth(48);
addRow(f.getName(), cb);
}
}
@@ -250,6 +255,8 @@ private void fillData() {
private void addRow(String string, View btn) {
TableLayout table = (TableLayout) findViewById(R.id.account_table);
TableRow row = new TableRow(this);
+ row.setMinimumHeight(48);
+ row.setMinimumWidth(48);
TextView title = new TextView(this);
title.setText(string);
row.addView(title);
@@ -333,7 +340,11 @@ public void onClick(View v) {
public void onClick(View v) {
final Intent intent = new Intent(Intent.ACTION_VIEW).setData(Uri.parse((String) v
.getTag()));
- startActivity(intent);
+ try {
+ startActivity(intent);
+ } catch (Exception e) {
+ Log.i(getClass().getName(), "No handler for file intent installed? " + e.getMessage());
+ }
}
};
diff --git a/app/src/main/org/runnerup/view/AudioCueSettingsActivity.java b/app/src/main/org/runnerup/view/AudioCueSettingsActivity.java
index ba746318e..d8c90dbf2 100644
--- a/app/src/main/org/runnerup/view/AudioCueSettingsActivity.java
+++ b/app/src/main/org/runnerup/view/AudioCueSettingsActivity.java
@@ -1,383 +1,386 @@
-/*
- * Copyright (C) 2013 jonas.oreland@gmail.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.runnerup.view;
-
-import android.support.v7.app.AlertDialog;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.Resources;
-import android.database.sqlite.SQLiteDatabase;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
-import android.preference.PreferenceActivity;
-import android.preference.PreferenceGroup;
-import android.preference.PreferenceManager;
-import android.speech.tts.TextToSpeech;
-import android.speech.tts.TextToSpeech.OnInitListener;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.EditText;
-
-import org.runnerup.R;
-import org.runnerup.common.util.Constants.DB;
-import org.runnerup.db.DBHelper;
-import org.runnerup.util.Formatter;
-import org.runnerup.util.HRZones;
-import org.runnerup.widget.TitleSpinner;
-import org.runnerup.widget.SpinnerInterface.OnSetValueListener;
-import org.runnerup.widget.WidgetUtil;
-import org.runnerup.workout.Feedback;
-import org.runnerup.workout.Workout;
-import org.runnerup.workout.WorkoutBuilder;
-import org.runnerup.workout.feedback.RUTextToSpeech;
-
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-
-
-public class AudioCueSettingsActivity extends PreferenceActivity {
-
- private boolean started = false;
- private boolean delete = false;
- private String settingsName = null;
- private AudioSchemeListAdapter adapter = null;
- private SQLiteDatabase mDB = null;
- private MenuItem newSettings;
-
- private String DEFAULT = "Default";
- public static final String SUFFIX = "_audio_cues";
- private static final String PREFS_DIR = "shared_prefs";
-
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- WidgetUtil.addLegacyOverflowButton(getWindow());
-
- mDB = DBHelper.getWritableDatabase(this);
- DEFAULT = getString(R.string.Default);
-
- Intent intent = getIntent();
- settingsName = intent.getStringExtra("name");
- if (settingsName != null) {
- PreferenceManager prefMgr = getPreferenceManager();
- prefMgr.setSharedPreferencesName(settingsName + SUFFIX);
- prefMgr.setSharedPreferencesMode(MODE_PRIVATE);
- }
-
- addPreferencesFromResource(R.xml.audio_cue_settings);
- setContentView(R.layout.settings_wrapper);
-
- {
- Preference btn = findPreference("test_cueinfo");
- btn.setOnPreferenceClickListener(onTestCueinfoClick);
- }
-
- HRZones hrZones = new HRZones(this);
- boolean hasHR = SettingsActivity.hasHR(this);
- boolean hasHRZones = hrZones.isConfigured();
-
- if (!hasHR || !hasHRZones) {
- final int remove[] = {
- R.string.cueinfo_total_hrz,
- R.string.cueinfo_step_hrz,
- R.string.cueinfo_lap_hrz,
- R.string.cueinfo_current_hrz
- };
- removePrefs(remove);
- }
-
- if (!hasHR) {
- final int remove[] = {
- R.string.cueinfo_total_hr,
- R.string.cueinfo_step_hr,
- R.string.cueinfo_lap_hr,
- R.string.cueinfo_current_hr
- };
- removePrefs(remove);
- }
-
- {
- Preference btn = findPreference("tts_settings");
- btn.setOnPreferenceClickListener(new OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
- Intent intent = new Intent()
- .setAction("com.android.settings.TTS_SETTINGS");
- startActivity(intent);
- return false;
- }
-
- });
- }
-
- final boolean createNewItem = true;
- adapter = new AudioSchemeListAdapter(mDB,
- (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE),
- createNewItem);
- adapter.reload();
-
- {
- TitleSpinner spinner = (TitleSpinner) findViewById(R.id.settings_spinner);
- spinner.setVisibility(View.VISIBLE);
- spinner.setAdapter(adapter);
-
- if (settingsName == null) {
- spinner.setValue(0);
- } else {
- int idx = adapter.find(settingsName);
- spinner.setValue(idx);
- }
- spinner.setOnSetValueListener(onSetValueListener);
- }
- }
-
- private void removePrefs(int[] remove) {
- Resources res = getResources();
- PreferenceGroup group = (PreferenceGroup) findPreference("cueinfo");
- if (group == null)
- return;
- for (int aRemove : remove) {
- String s = res.getString(aRemove);
- Preference pref = findPreference(s);
- group.removePreference(pref);
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (delete) {
- deleteAudioSchemeImpl(settingsName);
- }
- DBHelper.closeDB(mDB);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- newSettings = menu.add("New settings");
- MenuItem deleteMenuItem = menu.add("Delete settings");
- if (settingsName == null)
- deleteMenuItem.setEnabled(false);
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (item == newSettings) {
- createNewAudioSchemeDialog();
- return true;
- }
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setMessage(getString(R.string.Are_you_sure))
- .setPositiveButton(getString(R.string.Yes),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- dialog.dismiss();
- deleteAudioScheme();
- }
- })
- .setNegativeButton(getString(R.string.No),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- // Do nothing but close the dialog
- dialog.dismiss();
- }
-
- });
- builder.show();
- return true;
- }
-
- private void createNewAudioScheme(String scheme) {
- ContentValues tmp = new ContentValues();
- tmp.put(DB.AUDIO_SCHEMES.NAME, scheme);
- tmp.put(DB.AUDIO_SCHEMES.SORT_ORDER, 0);
- mDB.insert(DB.AUDIO_SCHEMES.TABLE, null, tmp);
- }
-
- private void deleteAudioScheme() {
- delete = true;
- getPreferenceManager().getSharedPreferences().edit().clear().apply();
- /*
- * Can only delete file in "next" activity...cause on destory on this,
- * will save file...
- */
-
- switchTo(null);
- }
-
- private void deleteAudioSchemeImpl(String name) {
- /*
- * Start by deleting file...then delete from table...so we don't get
- * stray files
- */
- File a = new File(getFilesDir().getAbsoluteFile() + "/../" + PREFS_DIR + "/" + name
- + SUFFIX + ".xml");
- //noinspection ResultOfMethodCallIgnored
- a.delete();
-
- String args[] = {
- name
- };
- mDB.delete(DB.AUDIO_SCHEMES.TABLE, DB.AUDIO_SCHEMES.NAME + "= ?", args);
- }
-
- private void updateSortOrder(String name) {
- mDB.execSQL("UPDATE " + DB.AUDIO_SCHEMES.TABLE + " set " + DB.AUDIO_SCHEMES.SORT_ORDER +
- " = (SELECT MAX(" + DB.AUDIO_SCHEMES.SORT_ORDER + ") + 1 FROM "
- + DB.AUDIO_SCHEMES.TABLE + ") " +
- " WHERE " + DB.AUDIO_SCHEMES.NAME + " = '" + name + "'");
- }
-
- private final OnSetValueListener onSetValueListener = new OnSetValueListener() {
-
- @Override
- public String preSetValue(String newValue)
- throws IllegalArgumentException {
- return newValue;
- }
-
- @Override
- public int preSetValue(int newValueId) throws IllegalArgumentException {
- String newValue = (String) adapter.getItem(newValueId);
- PreferenceManager prefMgr = getPreferenceManager();
- if (newValue.contentEquals(DEFAULT)) {
- prefMgr.getSharedPreferences().edit().apply();
- switchTo(null);
- } else if (newValue.contentEquals(getString(R.string.New_audio_scheme))) {
- createNewAudioSchemeDialog();
- } else {
- prefMgr.getSharedPreferences().edit().apply();
- updateSortOrder(newValue);
- switchTo(newValue);
- }
- throw new IllegalArgumentException();
- }
-
- };
-
- private void switchTo(String name) {
-
- if (!started) {
- // TODO investigate "spurious" onItemSelected during start
- started = true;
- return;
- }
-
- if (name == null && settingsName == null) {
- return;
- }
-
- if (name != null && settingsName != null && name.contentEquals(settingsName)) {
- return;
- }
-
- Intent i = new Intent(this, AudioCueSettingsActivity.class);
- if (name != null) {
- i.putExtra("name", name);
- }
- startActivity(i);
- finish();
- }
-
- private void createNewAudioSchemeDialog() {
- final EditText editText = new EditText(this);
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setTitle(getString(R.string.Create_new_audio_cue_scheme))
- // Get the layout inflater
- .setView(editText)
- .setPositiveButton(getString(R.string.Create), new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- String scheme = editText.getText().toString();
- if (!scheme.contentEquals("")) {
- createNewAudioScheme(scheme);
- updateSortOrder(scheme);
- switchTo(scheme);
- }
- }
- })
- .setNegativeButton(getString(R.string.Cancel), new OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- }
- });
- builder.show();
- }
-
- private final OnPreferenceClickListener onTestCueinfoClick = new OnPreferenceClickListener() {
-
- TextToSpeech tts = null;
- final ArrayList feedback = new ArrayList<>();
-
- private final OnInitListener mTTSOnInitListener = new OnInitListener() {
-
- @Override
- public void onInit(int arg0) {
- SharedPreferences prefs;
- if (settingsName == null || settingsName.contentEquals(DEFAULT))
- prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
- else
- prefs = getApplicationContext().getSharedPreferences(settingsName + SUFFIX,
- Context.MODE_PRIVATE);
- final boolean mute = prefs.getBoolean(getResources().getString(R.string.pref_mute_bool),
- false);
-
- Workout w = Workout.fakeWorkoutForTestingAudioCue();
- RUTextToSpeech rutts = new RUTextToSpeech(tts, mute, getApplicationContext());
- HashMap bindValues = new HashMap<>();
- bindValues.put(Workout.KEY_TTS, rutts);
- bindValues.put(Workout.KEY_FORMATTER, new Formatter(AudioCueSettingsActivity.this));
- bindValues.put(Workout.KEY_HRZONES, new HRZones(AudioCueSettingsActivity.this));
- w.onBind(w, bindValues);
- for (Feedback f : feedback) {
- f.onInit(w);
- f.onBind(w, bindValues);
- f.emit(w, AudioCueSettingsActivity.this.getApplicationContext());
- rutts.emit();
- }
- }
- };
-
- @Override
- public boolean onPreferenceClick(Preference arg0) {
- Context ctx = getApplicationContext();
- Resources res = getResources();
-
- feedback.clear();
- SharedPreferences prefs;
- if (settingsName == null || settingsName.contentEquals(DEFAULT))
- prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
- else
- prefs = ctx.getSharedPreferences(settingsName + SUFFIX, Context.MODE_PRIVATE);
-
- WorkoutBuilder.addFeedbackFromPreferences(prefs, res, feedback);
-
- tts = new TextToSpeech(ctx, mTTSOnInitListener);
- return false;
- }
- };
-}
+/*
+ * Copyright (C) 2013 jonas.oreland@gmail.com
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.runnerup.view;
+
+import android.support.v7.app.AlertDialog;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.Resources;
+import android.database.sqlite.SQLiteDatabase;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceClickListener;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceGroup;
+import android.preference.PreferenceManager;
+import android.speech.tts.TextToSpeech;
+import android.speech.tts.TextToSpeech.OnInitListener;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.EditText;
+
+import org.runnerup.R;
+import org.runnerup.common.util.Constants.DB;
+import org.runnerup.db.DBHelper;
+import org.runnerup.util.Formatter;
+import org.runnerup.util.HRZones;
+import org.runnerup.widget.TitleSpinner;
+import org.runnerup.widget.SpinnerInterface.OnSetValueListener;
+import org.runnerup.widget.WidgetUtil;
+import org.runnerup.workout.Feedback;
+import org.runnerup.workout.Workout;
+import org.runnerup.workout.WorkoutBuilder;
+import org.runnerup.workout.feedback.RUTextToSpeech;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+
+public class AudioCueSettingsActivity extends PreferenceActivity {
+
+ private boolean started = false;
+ private boolean delete = false;
+ private String settingsName = null;
+ private AudioSchemeListAdapter adapter = null;
+ private SQLiteDatabase mDB = null;
+ private MenuItem newSettings;
+
+ private String DEFAULT = "Default";
+ public static final String SUFFIX = "_audio_cues";
+ private static final String PREFS_DIR = "shared_prefs";
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WidgetUtil.addLegacyOverflowButton(getWindow());
+
+ mDB = DBHelper.getWritableDatabase(this);
+ DEFAULT = getString(R.string.Default);
+
+ Intent intent = getIntent();
+ settingsName = intent.getStringExtra("name");
+ if (settingsName != null) {
+ PreferenceManager prefMgr = getPreferenceManager();
+ prefMgr.setSharedPreferencesName(settingsName + SUFFIX);
+ prefMgr.setSharedPreferencesMode(MODE_PRIVATE);
+ }
+
+ addPreferencesFromResource(R.xml.audio_cue_settings);
+ setContentView(R.layout.settings_wrapper);
+
+ {
+ Preference btn = findPreference("test_cueinfo");
+ btn.setOnPreferenceClickListener(onTestCueinfoClick);
+ }
+
+ HRZones hrZones = new HRZones(this);
+ boolean hasHR = SettingsActivity.hasHR(this);
+ boolean hasHRZones = hrZones.isConfigured();
+
+ if (!hasHR || !hasHRZones) {
+ final int remove[] = {
+ R.string.cueinfo_total_hrz,
+ R.string.cueinfo_step_hrz,
+ R.string.cueinfo_lap_hrz,
+ R.string.cueinfo_current_hrz
+ };
+ removePrefs(remove);
+ }
+
+ if (!hasHR) {
+ final int remove[] = {
+ R.string.cueinfo_total_hr,
+ R.string.cueinfo_step_hr,
+ R.string.cueinfo_lap_hr,
+ R.string.cueinfo_current_hr
+ };
+ removePrefs(remove);
+ }
+
+ {
+ Preference btn = findPreference("tts_settings");
+ btn.setOnPreferenceClickListener(new OnPreferenceClickListener() {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ Intent intent = new Intent()
+ .setAction("com.android.settings.TTS_SETTINGS");
+ startActivity(intent);
+ return false;
+ }
+
+ });
+ }
+
+ final boolean createNewItem = true;
+ adapter = new AudioSchemeListAdapter(mDB,
+ (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE),
+ createNewItem);
+ adapter.reload();
+
+ {
+ TitleSpinner spinner = (TitleSpinner) findViewById(R.id.settings_spinner);
+ spinner.setVisibility(View.VISIBLE);
+ spinner.setAdapter(adapter);
+
+ if (settingsName == null) {
+ spinner.setValue(0);
+ } else {
+ int idx = adapter.find(settingsName);
+ spinner.setValue(idx);
+ }
+ spinner.setOnSetValueListener(onSetValueListener);
+ }
+ }
+
+ private void removePrefs(int[] remove) {
+ Resources res = getResources();
+ PreferenceGroup group = (PreferenceGroup) findPreference("cueinfo");
+ if (group == null)
+ return;
+ for (int aRemove : remove) {
+ String s = res.getString(aRemove);
+ Preference pref = findPreference(s);
+ group.removePreference(pref);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ if (delete) {
+ deleteAudioSchemeImpl(settingsName);
+ }
+ DBHelper.closeDB(mDB);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ newSettings = menu.add("New settings");
+ MenuItem deleteMenuItem = menu.add("Delete settings");
+ if (settingsName == null)
+ deleteMenuItem.setEnabled(false);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item == newSettings) {
+ createNewAudioSchemeDialog();
+ return true;
+ }
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setMessage(getString(R.string.Are_you_sure))
+ .setPositiveButton(getString(R.string.Yes),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ dialog.dismiss();
+ deleteAudioScheme();
+ }
+ })
+ .setNegativeButton(getString(R.string.No),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int which) {
+ // Do nothing but close the dialog
+ dialog.dismiss();
+ }
+
+ });
+ builder.show();
+ return true;
+ }
+
+ private void createNewAudioScheme(String scheme) {
+ ContentValues tmp = new ContentValues();
+ tmp.put(DB.AUDIO_SCHEMES.NAME, scheme);
+ tmp.put(DB.AUDIO_SCHEMES.SORT_ORDER, 0);
+ mDB.insert(DB.AUDIO_SCHEMES.TABLE, null, tmp);
+ }
+
+ private void deleteAudioScheme() {
+ delete = true;
+ getPreferenceManager().getSharedPreferences().edit().clear().apply();
+ /*
+ * Can only delete file in "next" activity...cause on destory on this,
+ * will save file...
+ */
+
+ switchTo(null);
+ }
+
+ private void deleteAudioSchemeImpl(String name) {
+ /*
+ * Start by deleting file...then delete from table...so we don't get
+ * stray files
+ */
+ File a = new File(getFilesDir().getAbsoluteFile() + "/../" + PREFS_DIR + "/" + name
+ + SUFFIX + ".xml");
+ //noinspection ResultOfMethodCallIgnored
+ a.delete();
+
+ String args[] = {
+ name
+ };
+ mDB.delete(DB.AUDIO_SCHEMES.TABLE, DB.AUDIO_SCHEMES.NAME + "= ?", args);
+ }
+
+ private void updateSortOrder(String name) {
+ mDB.execSQL("UPDATE " + DB.AUDIO_SCHEMES.TABLE + " set " + DB.AUDIO_SCHEMES.SORT_ORDER +
+ " = (SELECT MAX(" + DB.AUDIO_SCHEMES.SORT_ORDER + ") + 1 FROM "
+ + DB.AUDIO_SCHEMES.TABLE + ") " +
+ " WHERE " + DB.AUDIO_SCHEMES.NAME + " = '" + name + "'");
+ }
+
+ private final OnSetValueListener onSetValueListener = new OnSetValueListener() {
+
+ @Override
+ public String preSetValue(String newValue)
+ throws IllegalArgumentException {
+ return newValue;
+ }
+
+ @Override
+ public int preSetValue(int newValueId) throws IllegalArgumentException {
+ String newValue = (String) adapter.getItem(newValueId);
+ PreferenceManager prefMgr = getPreferenceManager();
+ if (newValue.contentEquals(DEFAULT)) {
+ prefMgr.getSharedPreferences().edit().apply();
+ switchTo(null);
+ } else if (newValue.contentEquals(getString(R.string.New_audio_scheme))) {
+ createNewAudioSchemeDialog();
+ } else {
+ prefMgr.getSharedPreferences().edit().apply();
+ updateSortOrder(newValue);
+ switchTo(newValue);
+ }
+ throw new IllegalArgumentException();
+ }
+
+ };
+
+ private void switchTo(String name) {
+
+ if (!started) {
+ // TODO investigate "spurious" onItemSelected during start
+ started = true;
+ return;
+ }
+
+ if (name == null && settingsName == null) {
+ return;
+ }
+
+ if (name != null && settingsName != null && name.contentEquals(settingsName)) {
+ return;
+ }
+
+ Intent i = new Intent(this, AudioCueSettingsActivity.class);
+ if (name != null) {
+ i.putExtra("name", name);
+ }
+ startActivity(i);
+ finish();
+ }
+
+ private void createNewAudioSchemeDialog() {
+ final EditText editText = new EditText(this);
+ editText.setMinimumHeight(48);
+ editText.setMinimumWidth(48);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this)
+ .setTitle(getString(R.string.Create_new_audio_cue_scheme))
+ // Get the layout inflater
+ .setView(editText)
+ .setPositiveButton(getString(R.string.OK), new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ String scheme = editText.getText().toString();
+ if (!scheme.contentEquals("")) {
+ createNewAudioScheme(scheme);
+ updateSortOrder(scheme);
+ switchTo(scheme);
+ }
+ }
+ })
+ .setNegativeButton(getString(R.string.Cancel), new OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ });
+ builder.show();
+ }
+
+ private final OnPreferenceClickListener onTestCueinfoClick = new OnPreferenceClickListener() {
+
+ TextToSpeech tts = null;
+ final ArrayList feedback = new ArrayList<>();
+
+ private final OnInitListener mTTSOnInitListener = new OnInitListener() {
+
+ @Override
+ public void onInit(int arg0) {
+ SharedPreferences prefs;
+ if (settingsName == null || settingsName.contentEquals(DEFAULT))
+ prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
+ else
+ prefs = getApplicationContext().getSharedPreferences(settingsName + SUFFIX,
+ Context.MODE_PRIVATE);
+ final boolean mute = prefs.getBoolean(getResources().getString(R.string.pref_mute_bool),
+ false);
+
+ Workout w = Workout.fakeWorkoutForTestingAudioCue();
+ RUTextToSpeech rutts = new RUTextToSpeech(tts, mute, getApplicationContext());
+ HashMap bindValues = new HashMap<>();
+ bindValues.put(Workout.KEY_TTS, rutts);
+ bindValues.put(Workout.KEY_FORMATTER, new Formatter(AudioCueSettingsActivity.this));
+ bindValues.put(Workout.KEY_HRZONES, new HRZones(AudioCueSettingsActivity.this));
+ w.onBind(w, bindValues);
+ for (Feedback f : feedback) {
+ f.onInit(w);
+ f.onBind(w, bindValues);
+ f.emit(w, AudioCueSettingsActivity.this.getApplicationContext());
+ rutts.emit();
+ }
+ }
+ };
+
+ @Override
+ public boolean onPreferenceClick(Preference arg0) {
+ Context ctx = getApplicationContext();
+ Resources res = getResources();
+
+ feedback.clear();
+ SharedPreferences prefs;
+ if (settingsName == null || settingsName.contentEquals(DEFAULT))
+ prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
+ else
+ prefs = ctx.getSharedPreferences(settingsName + SUFFIX, Context.MODE_PRIVATE);
+
+ WorkoutBuilder.addFeedbackFromPreferences(prefs, res, feedback);
+
+ tts = new TextToSpeech(ctx, mTTSOnInitListener);
+ return false;
+ }
+ };
+}
diff --git a/app/src/main/org/runnerup/view/MainLayout.java b/app/src/main/org/runnerup/view/MainLayout.java
index cd2e8b323..4522e7c4e 100644
--- a/app/src/main/org/runnerup/view/MainLayout.java
+++ b/app/src/main/org/runnerup/view/MainLayout.java
@@ -78,7 +78,7 @@ private Drawable myGetDrawable(int resId) {
private View getTabView(CharSequence label, int iconResource) {
@SuppressLint("InflateParams")View tabView = getLayoutInflater().inflate(R.layout.bottom_tab_indicator, null);
- // ((TextView)tabView.findViewById(R.id.title)).setText(label);
+ ((ImageView)tabView.findViewById(R.id.icon)).setContentDescription(label);
Drawable icon = ContextCompat.getDrawable(this, iconResource);
((ImageView)tabView.findViewById(R.id.icon)).setImageDrawable(icon);
return tabView;
diff --git a/app/src/main/org/runnerup/view/ManageWorkoutsActivity.java b/app/src/main/org/runnerup/view/ManageWorkoutsActivity.java
index 109feb91b..4b4b719e8 100644
--- a/app/src/main/org/runnerup/view/ManageWorkoutsActivity.java
+++ b/app/src/main/org/runnerup/view/ManageWorkoutsActivity.java
@@ -234,7 +234,7 @@ public void onClick(DialogInterface dialog, int which) {
launchMain(saveName);
}
})
- .setNegativeButton(getString(R.string.No_way),
+ .setNegativeButton(getString(R.string.No),
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Do nothing but close the dialog
diff --git a/app/src/main/org/runnerup/widget/DistancePicker.java b/app/src/main/org/runnerup/widget/DistancePicker.java
index 99e3f7d9c..de37f8543 100644
--- a/app/src/main/org/runnerup/widget/DistancePicker.java
+++ b/app/src/main/org/runnerup/widget/DistancePicker.java
@@ -44,6 +44,8 @@ public DistancePicker(Context context, AttributeSet attrs) {
LayoutParams.MATCH_PARENT));
unitString = new TextView(context, attrs);
unitString.setTextSize(25);
+ unitString.setMinimumHeight(48);
+ unitString.setMinimumWidth(48);
unitStringLayout.addView(unitString);
meters = new NumberPicker(context, attrs);
diff --git a/app/src/main/org/runnerup/widget/DurationPicker.java b/app/src/main/org/runnerup/widget/DurationPicker.java
index da96c1299..12a06db18 100644
--- a/app/src/main/org/runnerup/widget/DurationPicker.java
+++ b/app/src/main/org/runnerup/widget/DurationPicker.java
@@ -32,8 +32,14 @@ public DurationPicker(Context context, AttributeSet attrs) {
super(context, attrs);
hours = new NumberPicker(context, attrs);
+ hours.setMinimumHeight(48);
+ hours.setMinimumWidth(48);
minutes = new NumberPicker(context, attrs);
+ minutes.setMinimumHeight(48);
+ minutes.setMinimumWidth(48);
seconds = new NumberPicker(context, attrs);
+ seconds.setMinimumHeight(48);
+ seconds.setMinimumWidth(48);
hours.setOrientation(VERTICAL);
minutes.setOrientation(VERTICAL);
diff --git a/app/src/main/org/runnerup/widget/SpinnerPresenter.java b/app/src/main/org/runnerup/widget/SpinnerPresenter.java
index ff004f1bf..510678157 100644
--- a/app/src/main/org/runnerup/widget/SpinnerPresenter.java
+++ b/app/src/main/org/runnerup/widget/SpinnerPresenter.java
@@ -149,6 +149,8 @@ private void setupEditText(final Context context, final AttributeSet attrs, Type
public void onClick(View v) {
edit.setText(mSpin.getViewValueText());
edit.setInputType(mInputType);
+ edit.setMinimumHeight(48);
+ edit.setMinimumWidth(148);
if(edit.getParent() != null) {
((LinearLayout)edit.getParent()).removeView(edit);
}
diff --git a/app/src/main/org/runnerup/widget/TextPreference.java b/app/src/main/org/runnerup/widget/TextPreference.java
index c0266f466..9f82b1551 100644
--- a/app/src/main/org/runnerup/widget/TextPreference.java
+++ b/app/src/main/org/runnerup/widget/TextPreference.java
@@ -29,26 +29,23 @@ public class TextPreference extends android.preference.EditTextPreference {
public TextPreference(Context context) {
super(context);
- this.context = context;
}
public TextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
- this.context = context;
}
public TextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- this.context = context;
}
- private final Context context;
-
@Override
protected void onSetInitialValue(boolean restorePersistedValue,
Object defaultValue) {
super.onSetInitialValue(restorePersistedValue, defaultValue);
super.setSummary(super.getPersistedString(""));
+ super.getEditText().setMinimumWidth(48);
+ super.getEditText().setMinimumHeight(48);
}
@Override
@@ -61,7 +58,7 @@ protected void onDialogClosed(boolean ok) {
//This could be a default setting and should not be hardcoded in a widget
//However, getting the default value in the xml seems hard and a similar
//onPreferenceChange() in SettingsActivity is not much better
- Resources res = context.getResources();
+ Resources res = getContext().getResources();
if (this.getKey().equals(res.getString(R.string.pref_mapbox_default_style))) {
val = res.getString(R.string.mapboxDefaultStyle);
super.setText(val);
diff --git a/app/src/main/play/listings/en-US/short-description.txt b/app/src/main/play/listings/en-US/short-description.txt
deleted file mode 100644
index 6024a5c96..000000000
--- a/app/src/main/play/listings/en-US/short-description.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-RunnerUp, an open source run tracker with advanced workout and audio cues.
-Track your running with RunnerUp using the GPS in your Android phone.
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 430dd6a3a..b4f8bd184 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,7 +4,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.0'
+ classpath 'com.android.tools.build:gradle:4.0.1'
}
}
@@ -29,9 +29,10 @@ project.ext {
junitVersion = '4.12'
mockitoVersion = '2.3.7'
- //The tag for the release must be identical for F-Droid
- versionName = '2.0.6.4'
- versionCode = 214
+ //The Git tag for the release must be identical for F-Droid
+ versionName = '2.1.0.0'
+ versionCode = 240
+ latestBaseVersionCode = 14000000
travisBuild = System.getenv("TRAVIS") == "true"
// allows for -Dpre-dex=false to be set
@@ -39,6 +40,7 @@ project.ext {
// F-Droid builds only allow free software (wear dir deleted at builds)
allowNonFree = !project.hasProperty('org.runnerup.free') && rootProject.file("wear").exists()
+ enableWear = allowNonFree
// Note: AntPlus may have to be downloaded explicitly due to licensing
antPlusLib = "ANT-Android-SDKs/ANT+_Android_SDK/API/antpluginlib_3-8-0.aar"
diff --git a/common/src/main/res/values-tr/strings.xml b/common/src/main/res/values-tr/strings.xml
index 4b8bd6c7a..47fccfce3 100644
--- a/common/src/main/res/values-tr/strings.xml
+++ b/common/src/main/res/values-tr/strings.xml
@@ -24,7 +24,6 @@
- TamamTiptoparlanma
@@ -56,5 +55,4 @@
YenileYaşTamam
- Tamam
diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml
index 7a2d11db5..0d1fe85fe 100644
--- a/common/src/main/res/values/strings.xml
+++ b/common/src/main/res/values/strings.xml
@@ -151,7 +151,6 @@
Create new audio cue schemeYesCreate
- No wayNoLoadingSaving
diff --git a/gradle.properties b/gradle.properties
index e69de29bb..fffbac400 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -0,0 +1 @@
+android.enableR8=false
\ No newline at end of file
diff --git a/wear/build.gradle b/wear/build.gradle
index 3e9dc309b..73bae494b 100644
--- a/wear/build.gradle
+++ b/wear/build.gradle
@@ -1,6 +1,5 @@
apply plugin: 'com.android.application'
-
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
@@ -9,7 +8,7 @@ android {
minSdkVersion 23
targetSdkVersion rootProject.ext.compileSdkVersion
versionName rootProject.ext.versionName
- versionCode rootProject.ext.versionCode
+ versionCode rootProject.ext.latestBaseVersionCode + rootProject.ext.versionCode
}
dexOptions {
diff --git a/wear/lint-baseline.xml b/wear/lint-baseline.xml
index 177e58b3b..9cd5a767a 100644
--- a/wear/lint-baseline.xml
+++ b/wear/lint-baseline.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/wear/proguard.txt b/wear/proguard.txt
index 38814c6e9..60620f7a3 100644
--- a/wear/proguard.txt
+++ b/wear/proguard.txt
@@ -3,3 +3,4 @@
#PlayServices related?
-dontnote com.google.protobuf.zz*
-dontnote com.google.android.gms.dynamic.IObjectWrapper
+-dontwarn com.google.android.wearable.**
diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml
index 54b2e61d9..0deb26aaf 100644
--- a/wear/src/main/AndroidManifest.xml
+++ b/wear/src/main/AndroidManifest.xml
@@ -30,10 +30,6 @@
android:supportsRtl="true"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
-
-