Merge branch 'dev' into 2kotlin-androidbase

pull/596/head
Alinson S. Xavier 5 years ago
commit d5a840388c

@ -878,7 +878,7 @@ public class TimePickerDialog extends AppCompatDialogFragment implements OnValue
// When the first digit is 2, the second digit may be 4-5. // When the first digit is 2, the second digit may be 4-5.
secondDigit = new Node(k4, k5); secondDigit = new Node(k4, k5);
firstDigit.addChild(secondDigit); firstDigit.addChild(secondDigit);
// We must now be followd by the last minute digit. E.g. 2:40, 2:53. // We must now be followed by the last minute digit. E.g. 2:40, 2:53.
secondDigit.addChild(minuteSecondDigit); secondDigit.addChild(minuteSecondDigit);
// The first digit may be 3-9. // The first digit may be 3-9.

@ -25,294 +25,255 @@ OUTPUTS_DIR=uhabits-android/build/outputs
VERSION=$(cat gradle.properties | grep VERSION_NAME | sed -e 's/.*=//g;s/ //g') VERSION=$(cat gradle.properties | grep VERSION_NAME | sed -e 's/.*=//g;s/ //g')
if [ ! -f "${ANDROID_HOME}/platform-tools/adb" ]; then if [ ! -f "${ANDROID_HOME}/platform-tools/adb" ]; then
echo "Error: ANDROID_HOME is not set correctly" echo "Error: ANDROID_HOME is not set correctly"
exit 1 exit 1
fi fi
log_error() { log_error() {
if [ ! -z "$TEAMCITY_VERSION" ]; then if [ ! -z "$TEAMCITY_VERSION" ]; then
echo "###teamcity[progressMessage '$1']" echo "###teamcity[progressMessage '$1']"
else else
local COLOR='\033[1;31m' local COLOR='\033[1;31m'
local NC='\033[0m' local NC='\033[0m'
echo -e "$COLOR>>> $1 $NC" echo -e "$COLOR>>> $1 $NC"
fi fi
} }
log_info() { log_info() {
if [ ! -z "$TEAMCITY_VERSION" ]; then if [ ! -z "$TEAMCITY_VERSION" ]; then
echo "###teamcity[progressMessage '$1']" echo "###teamcity[progressMessage '$1']"
else else
local COLOR='\033[1;32m' local COLOR='\033[1;32m'
local NC='\033[0m' local NC='\033[0m'
echo -e "$COLOR>>> $1 $NC" echo -e "$COLOR>>> $1 $NC"
fi fi
} }
fail() { fail() {
if [ ! -z ${AVD_NAME} ]; then log_error "BUILD FAILED"
stop_emulator exit 1
stop_gradle_daemon
fi
log_error "BUILD FAILED"
exit 1
} }
if [ ! -z $RELEASE ]; then if [ ! -z $RELEASE ]; then
log_info "Reading secret env variables from ../.secret/env" log_info "Reading secret env variables from ../.secret/env"
source ../.secret/env || fail source ../.secret/env || fail
fi fi
start_emulator() {
log_info "Starting emulator ($AVD_NAME)"
$EMULATOR -avd ${AVD_NAME} -port ${AVD_SERIAL} -no-audio -no-window &
$ADB wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; input keyevent 82'
}
stop_emulator() {
log_info "Stopping emulator"
$ADB emu kill
}
stop_gradle_daemon() {
log_info "Stopping gradle daemon"
$GRADLE --stop
}
run_adb_as_root() { run_adb_as_root() {
log_info "Running adb as root" log_info "Running adb as root"
$ADB root $ADB root
} }
build_apk() { build_apk() {
log_info "Removing old APKs..." log_info "Removing old APKs..."
rm -vf build/*.apk rm -vf build/*.apk
if [ ! -z $RELEASE ]; then if [ ! -z $RELEASE ]; then
log_info "Building release APK" log_info "Building release APK"
./gradlew assembleRelease ./gradlew assembleRelease
cp -v uhabits-android/build/outputs/apk/release/uhabits-android-release.apk build/loop-$VERSION-release.apk cp -v uhabits-android/build/outputs/apk/release/uhabits-android-release.apk build/loop-$VERSION-release.apk
fi fi
log_info "Building debug APK" log_info "Building debug APK"
./gradlew assembleDebug || fail ./gradlew assembleDebug || fail
cp -v uhabits-android/build/outputs/apk/debug/uhabits-android-debug.apk build/loop-$VERSION-debug.apk cp -v uhabits-android/build/outputs/apk/debug/uhabits-android-debug.apk build/loop-$VERSION-debug.apk
} }
build_instrumentation_apk() { build_instrumentation_apk() {
log_info "Building instrumentation APK" log_info "Building instrumentation APK"
if [ ! -z $RELEASE ]; then if [ ! -z $RELEASE ]; then
$GRADLE assembleAndroidTest \ $GRADLE assembleAndroidTest \
-Pandroid.injected.signing.store.file=$LOOP_KEY_STORE \ -Pandroid.injected.signing.store.file=$LOOP_KEY_STORE \
-Pandroid.injected.signing.store.password=$LOOP_STORE_PASSWORD \ -Pandroid.injected.signing.store.password=$LOOP_STORE_PASSWORD \
-Pandroid.injected.signing.key.alias=$LOOP_KEY_ALIAS \ -Pandroid.injected.signing.key.alias=$LOOP_KEY_ALIAS \
-Pandroid.injected.signing.key.password=$LOOP_KEY_PASSWORD || fail -Pandroid.injected.signing.key.password=$LOOP_KEY_PASSWORD || fail
else else
$GRADLE assembleAndroidTest || fail $GRADLE assembleAndroidTest || fail
fi fi
}
clean_output_dir() {
log_info "Cleaning output directory"
rm -rf ${OUTPUTS_DIR}
mkdir -p ${OUTPUTS_DIR}
} }
uninstall_apk() { uninstall_apk() {
log_info "Uninstalling existing APK" log_info "Uninstalling existing APK"
$ADB uninstall ${PACKAGE_NAME} $ADB uninstall ${PACKAGE_NAME}
} }
install_test_butler() { install_test_butler() {
log_info "Installing Test Butler" log_info "Installing Test Butler"
$ADB uninstall com.linkedin.android.testbutler $ADB uninstall com.linkedin.android.testbutler
$ADB install tools/test-butler-app-2.0.2.apk $ADB install tools/test-butler-app-2.0.2.apk
} }
install_apk() { install_apk() {
log_info "Installing APK" log_info "Installing APK"
if [ ! -z $RELEASE ]; then if [ ! -z $RELEASE ]; then
$ADB install -r ${OUTPUTS_DIR}/apk/release/uhabits-android-release.apk || fail $ADB install -r ${OUTPUTS_DIR}/apk/release/uhabits-android-release.apk || fail
else else
$ADB install -t -r ${OUTPUTS_DIR}/apk/debug/uhabits-android-debug.apk || fail $ADB install -t -r ${OUTPUTS_DIR}/apk/debug/uhabits-android-debug.apk || fail
fi fi
} }
install_test_apk() { install_test_apk() {
log_info "Uninstalling existing test APK" log_info "Uninstalling existing test APK"
$ADB uninstall ${PACKAGE_NAME}.test $ADB uninstall ${PACKAGE_NAME}.test
log_info "Installing test APK" log_info "Installing test APK"
$ADB install -r ${OUTPUTS_DIR}/apk/androidTest/debug/uhabits-android-debug-androidTest.apk || fail $ADB install -r ${OUTPUTS_DIR}/apk/androidTest/debug/uhabits-android-debug-androidTest.apk || fail
} }
run_instrumented_tests() { run_instrumented_tests() {
SIZE=$1 SIZE=$1
log_info "Running instrumented tests" log_info "Running instrumented tests"
$ADB shell am instrument \ $ADB shell am instrument \
-r -e coverage true -e size $SIZE \ -r -e coverage true -e size $SIZE \
-w ${PACKAGE_NAME}.test/android.support.test.runner.AndroidJUnitRunner \ -w ${PACKAGE_NAME}.test/androidx.test.runner.AndroidJUnitRunner \
| tee ${OUTPUTS_DIR}/instrument.txt | tee ${OUTPUTS_DIR}/instrument.txt
if grep FAILURES $OUTPUTS_DIR/instrument.txt; then if grep "\(INSTRUMENTATION_STATUS_CODE.*-1\|FAILURES\)" $OUTPUTS_DIR/instrument.txt; then
log_error "Some instrumented tests failed" log_error "Some instrumented tests failed"
fetch_images fetch_images
fetch_logcat fetch_logcat
exit 1 exit 1
fi fi
#mkdir -p ${OUTPUTS_DIR}/code-coverage/connected/ #mkdir -p ${OUTPUTS_DIR}/code-coverage/connected/
#$ADB pull /data/user/0/${PACKAGE_NAME}/files/coverage.ec \ #$ADB pull /data/user/0/${PACKAGE_NAME}/files/coverage.ec \
# ${OUTPUTS_DIR}/code-coverage/connected/ \ # ${OUTPUTS_DIR}/code-coverage/connected/ \
# || log_error "COVERAGE REPORT NOT AVAILABLE" # || log_error "COVERAGE REPORT NOT AVAILABLE"
} }
parse_instrumentation_results() { parse_instrumentation_results() {
log_info "Parsing instrumented test results" log_info "Parsing instrumented test results"
java -jar tools/automator-log-converter-1.5.0.jar ${OUTPUTS_DIR}/instrument.txt || fail java -jar tools/automator-log-converter-1.5.0.jar ${OUTPUTS_DIR}/instrument.txt || fail
} }
generate_coverage_badge() { generate_coverage_badge() {
log_info "Generating code coverage badge" log_info "Generating code coverage badge"
CORE_REPORT=uhabits-core/build/reports/jacoco/test/jacocoTestReport.xml CORE_REPORT=uhabits-core/build/reports/jacoco/test/jacocoTestReport.xml
rm -f ${OUTPUTS_DIR}/coverage-badge.svg rm -f ${OUTPUTS_DIR}/coverage-badge.svg
python3 tools/coverage-badge/badge.py -i $CORE_REPORT -o ${OUTPUTS_DIR}/coverage-badge python3 tools/coverage-badge/badge.py -i $CORE_REPORT -o ${OUTPUTS_DIR}/coverage-badge
} }
fetch_logcat() { fetch_logcat() {
log_info "Fetching logcat" log_info "Fetching logcat"
$ADB logcat -d > ${OUTPUTS_DIR}/logcat.txt $ADB logcat -d > ${OUTPUTS_DIR}/logcat.txt
} }
run_jvm_tests() { run_jvm_tests() {
log_info "Running JVM tests" log_info "Running JVM tests"
if [ ! -z $RELEASE ]; then if [ ! -z $RELEASE ]; then
$GRADLE testReleaseUnitTest :uhabits-core:check || fail $GRADLE testReleaseUnitTest :uhabits-core:check || fail
else else
$GRADLE testDebugUnitTest :uhabits-core:check || fail $GRADLE testDebugUnitTest :uhabits-core:check || fail
fi fi
} }
uninstall_test_apk() { uninstall_test_apk() {
log_info "Uninstalling test APK" log_info "Uninstalling test APK"
$ADB uninstall ${PACKAGE_NAME}.test $ADB uninstall ${PACKAGE_NAME}.test
} }
fetch_images() { fetch_images() {
log_info "Fetching images" log_info "Fetching images"
rm -rf $OUTPUTS_DIR/test-screenshots rm -rf $OUTPUTS_DIR/test-screenshots
$ADB pull /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/ $OUTPUTS_DIR $ADB pull /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/ $OUTPUTS_DIR
$ADB shell rm -r /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/ $ADB shell rm -r /sdcard/Android/data/${PACKAGE_NAME}/files/test-screenshots/
} }
accept_images() { accept_images() {
find tmp/test-screenshots -name '*.expected*' -delete find tmp/test-screenshots -name '*.expected*' -delete
rsync -av tmp/test-screenshots/ uhabits-android/src/androidTest/assets/ rsync -av tmp/test-screenshots/ uhabits-android/src/androidTest/assets/
} }
run_tests() { run_tests() {
SIZE=$1 SIZE=$1
run_adb_as_root run_adb_as_root
install_test_butler install_test_butler
uninstall_apk uninstall_apk
install_apk install_apk
install_test_apk install_test_apk
run_instrumented_tests $SIZE run_instrumented_tests $SIZE
parse_instrumentation_results parse_instrumentation_results
fetch_logcat fetch_logcat
uninstall_test_apk uninstall_test_apk
} }
parse_opts() { parse_opts() {
OPTS=`getopt -o ur --long uninstall-first,release -n 'build.sh' -- "$@"` OPTS=`getopt -o r --long release -n 'build.sh' -- "$@"`
if [ $? != 0 ] ; then exit 1; fi if [ $? != 0 ] ; then exit 1; fi
eval set -- "$OPTS" eval set -- "$OPTS"
while true; do while true; do
case "$1" in case "$1" in
-u | --uninstall-first ) UNINSTALL_FIRST=1; shift ;; -r | --release ) RELEASE=1; shift ;;
-r | --release ) RELEASE=1; shift ;; * ) break ;;
* ) break ;; esac
esac done
done }
remove_build_dir() {
rm -rfv build
rm -rfv android-base/build
rm -rfv android-pickers/build
rm -rfv uhabits-android/build
rm -rfv uhabits-core/build
} }
case "$1" in case "$1" in
build) build)
shift; parse_opts $* shift; parse_opts $*
build_apk build_apk
build_instrumentation_apk build_instrumentation_apk
run_jvm_tests run_jvm_tests
#generate_coverage_badge #generate_coverage_badge
;; ;;
ci-tests) medium-tests)
if [ -z $3 ]; then shift; parse_opts $*
cat <<- END run_tests medium
Usage: $0 ci-tests AVD_NAME AVD_SERIAL [options] ;;
Parameters: large-tests)
AVD_NAME name of the virtual android device to start shift; parse_opts $*
AVD_SERIAL adb port to use (e.g. 5560) run_tests large
;;
Options:
-u --uninstall-first Uninstall existing APK first fetch-images)
-r --release Test release APK, instead of debug fetch_images
END ;;
exit 1
fi accept-images)
accept_images
shift; AVD_NAME=$1 ;;
shift; AVD_SERIAL=$1
shift; parse_opts $* install)
ADB="${ADB} -s emulator-${AVD_SERIAL}" shift; parse_opts $*
build_apk
start_emulator install_apk
run_tests medium ;;
stop_emulator
stop_gradle_daemon clean)
;; remove_build_dir
;;
medium-tests)
shift; parse_opts $* *)
run_tests medium cat <<END
;; Usage: $0 <command> [options]
Builds, installs and tests Loop Habit Tracker
large-tests)
shift; parse_opts $* Commands:
run_tests large accept-images Copies fetched images to corresponding assets folder
;; build Build APK and run JVM tests
clean Remove build directory
fetch-images) fetch-images Fetches failed view test images from device
fetch_images install Install app on connected device
;; large-tests Run large-sized tests on connected device
medium-tests Run medium-sized tests on connected device
accept-images)
accept_images Options:
;; -r --release Build and test release APK, instead of debug
END
install) exit 1
shift; parse_opts $* ;;
build_apk
install_apk
;;
*)
cat <<- END
Usage: $0 <command> [options]
Builds, installs and tests Loop Habit Tracker
Commands:
ci-tests Start emulator silently, run tests then kill emulator
local-tests Run all tests on connected device
install Install app on connected device
fetch-images Fetches failed view test images from device
accept-images Copies fetched images to corresponding assets folder
Options:
-r --release Build and test release APK, instead of debug
END
exit 1
esac esac

@ -55,7 +55,7 @@ def get_total(report):
def get_color(total): def get_color(total):
""" """
Return color for current coverage precent Return color for current coverage percent
""" """
try: try:
xtotal = int(total) xtotal = int(total)

@ -1,61 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker 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.
*
* Loop Habit Tracker 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 <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.tasks;
import androidx.test.filters.*;
import androidx.test.runner.*;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.isoron.uhabits.*;
import org.junit.*;
import org.junit.runner.*;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class ExportCSVTaskTest extends BaseAndroidTest
{
@Before
@Override
public void setUp()
{
super.setUp();
}
// @Test
// public void testExportCSV() throws Throwable
// {
// fixtures.purgeHabits(habitList);
// fixtures.createShortHabit();
//
// List<Habit> selected = new LinkedList<>();
// for (Habit h : habitList) selected.add(h);
// File outputDir = new AndroidDirFinder(targetContext).getFilesDir("CSV");
// assertNotNull(outputDir);
//
// taskRunner.execute(
// new ExportCSVTask(habitList, selected, outputDir, archiveFilename -> {
// assertThat(archiveFilename, is(not(nullValue())));
// File f = new File(archiveFilename);
// assertTrue(f.exists());
// assertTrue(f.canRead());
// }));
// }
}

@ -1,57 +0,0 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker 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.
*
* Loop Habit Tracker 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 <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.tasks;
import androidx.test.filters.*;
import androidx.test.runner.*;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.isoron.uhabits.*;
import org.junit.*;
import org.junit.runner.*;
@RunWith(AndroidJUnit4.class)
@MediumTest
public class ExportDBTaskTest extends BaseAndroidTest
{
@Override
@Before
public void setUp()
{
super.setUp();
}
// @Test
// public void testExportCSV() throws Throwable
// {
// ExportDBTask task =
// new ExportDBTask(targetContext, new AndroidDirFinder(targetContext),
// filename ->
// {
// assertNotNull(filename);
// File f = new File(filename);
// assertTrue(f.exists());
// assertTrue(f.canRead());
// });
//
// taskRunner.execute(task);
// }
}

@ -123,7 +123,7 @@
<string-array name="targetIntervals" translatable="false"> <string-array name="targetIntervals" translatable="false">
<item>daily</item> <item>daily</item>
<item>weekly</item> <item>weekly</item>
<item>montly</item> <item>monthly</item>
</string-array> </string-array>
<string name="snooze_interval_default" translatable="false">15</string> <string name="snooze_interval_default" translatable="false">15</string>

@ -57,7 +57,7 @@ public class Repository<T>
* Returns all records matching the given SQL query. * Returns all records matching the given SQL query.
* <p> * <p>
* The query should only contain the "where" part of the SQL query, and * The query should only contain the "where" part of the SQL query, and
* optinally the "order by" part. "Group by" is not allowed. If no matching * optionally the "order by" part. "Group by" is not allowed. If no matching
* records are found, returns an empty list. * records are found, returns an empty list.
*/ */
@NonNull @NonNull

@ -123,7 +123,7 @@ public abstract class StreakList
* habit to not performing a habit, and vice-versa. * habit to not performing a habit, and vice-versa.
* *
* @param beginning the timestamp for the first checkmark * @param beginning the timestamp for the first checkmark
* @param checks the checkmarks, ordered by decresing timestamp * @param checks the checkmarks, ordered by decreasing timestamp
* @return the list of transitions * @return the list of transitions
*/ */
@NonNull @NonNull

@ -32,7 +32,7 @@ The repository will be downloaded to the directory `uhabits`. The Android files
1. Launch Android Studio and select "Open an existing Android Studio project". 1. Launch Android Studio and select "Open an existing Android Studio project".
2. When the IDE asks you for the project location, select `uhabits/android` and click "Ok". 2. When the IDE asks you for the project location, select `uhabits/android` and click "Ok".
3. Android Studio will spend some time indexing the project. When this is complete, click the toolbar icon "Sync Project with Gradle File", located near the right corner of the top toolbar. 3. Android Studio will spend some time indexing the project. When this is complete, click the toolbar icon "Sync Project with Gradle File", located near the right corner of the top toolbar.
4. The operation will likely fail several times due to missing Android SDK components. Each time it fails, click the link "Install missing platforms", "Instal build tools", etc, and try again. 4. The operation will likely fail several times due to missing Android SDK components. Each time it fails, click the link "Install missing platforms", "Install build tools", etc, and try again.
5. To test the application, create a virtual Android device using the menu "Tools" and "AVD Manager". The default options should work fine, but free to customize the device. 5. To test the application, create a virtual Android device using the menu "Tools" and "AVD Manager". The default options should work fine, but free to customize the device.
6. Click the menu "Run" and "uhabits-android". The application should launch. 6. Click the menu "Run" and "uhabits-android". The application should launch.

Loading…
Cancel
Save