├── app
├── proguard-rules.pro
├── src
│ └── main
│ │ ├── res
│ │ ├── raw
│ │ │ └── bip.ogg
│ │ ├── drawable-hdpi
│ │ │ ├── ic_fine.png
│ │ │ └── ic_coarse.png
│ │ ├── drawable-ldpi
│ │ │ ├── ic_fine.png
│ │ │ └── ic_coarse.png
│ │ ├── drawable-mdpi
│ │ │ ├── ic_fine.png
│ │ │ └── ic_coarse.png
│ │ ├── drawable-xhdpi
│ │ │ ├── ic_fine.png
│ │ │ └── ic_coarse.png
│ │ ├── drawable-xxhdpi
│ │ │ ├── ic_fine.png
│ │ │ └── ic_coarse.png
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable
│ │ │ ├── baseline_height_black_24dp.png
│ │ │ ├── ic_info.xml
│ │ │ ├── ic_ruler.xml
│ │ │ ├── ic_reset.xml
│ │ │ ├── ic_calibrate.xml
│ │ │ ├── ic_settings.xml
│ │ │ ├── ic_bubble.xml
│ │ │ ├── ic_coarse.xml
│ │ │ ├── ic_launcher_monochrome.xml
│ │ │ ├── ic_launcher_foreground.xml
│ │ │ └── ic_fine.xml
│ │ ├── values
│ │ │ ├── ic_launcher_background.xml
│ │ │ ├── attrs.xml
│ │ │ ├── config.xml
│ │ │ ├── themes.xml
│ │ │ ├── dimens.xml
│ │ │ ├── pref_arrays.xml
│ │ │ ├── pref_keys.xml
│ │ │ ├── colors.xml
│ │ │ └── strings.xml
│ │ ├── drawable-nodpi
│ │ │ ├── marker_2d.xml
│ │ │ ├── marker_1d.xml
│ │ │ ├── bubble.xml
│ │ │ ├── display.xml
│ │ │ ├── level_1d.xml
│ │ │ └── level_2d.xml
│ │ ├── mipmap-anydpi-v26
│ │ │ └── ic_launcher.xml
│ │ ├── layout
│ │ │ ├── settings_activity.xml
│ │ │ └── main.xml
│ │ ├── menu
│ │ │ └── main.xml
│ │ ├── values-zh
│ │ │ └── strings.xml
│ │ ├── values-zh-rCN
│ │ │ └── strings.xml
│ │ ├── xml
│ │ │ └── preferences.xml
│ │ ├── values-pt-rBR
│ │ │ └── strings.xml
│ │ ├── values-es
│ │ │ └── strings.xml
│ │ ├── values-nl
│ │ │ └── strings.xml
│ │ ├── values-pt
│ │ │ └── strings.xml
│ │ ├── values-cs
│ │ │ └── strings.xml
│ │ ├── values-nb
│ │ │ └── strings.xml
│ │ ├── values-it
│ │ │ └── strings.xml
│ │ ├── values-de
│ │ │ └── strings.xml
│ │ ├── values-tr
│ │ │ └── strings.xml
│ │ ├── values-ru
│ │ │ └── strings.xml
│ │ ├── values-fr
│ │ │ └── strings.xml
│ │ ├── values-eu
│ │ │ └── strings.xml
│ │ └── values-el
│ │ │ └── strings.xml
│ │ ├── assets
│ │ └── fonts
│ │ │ └── lcd.ttf
│ │ ├── ic_launcher-playstore.png
│ │ ├── java
│ │ └── org
│ │ │ └── woheller69
│ │ │ └── level
│ │ │ ├── LevelApp.java
│ │ │ ├── util
│ │ │ ├── PrefKeys.java
│ │ │ └── PreferenceHelper.java
│ │ │ ├── orientation
│ │ │ ├── OrientationListener.java
│ │ │ ├── Orientation.java
│ │ │ └── OrientationProvider.java
│ │ │ ├── SettingsFragment.java
│ │ │ ├── SettingsActivity.java
│ │ │ ├── view
│ │ │ ├── LevelView.java
│ │ │ ├── VerticalSeekBar.java
│ │ │ └── RulerView.java
│ │ │ └── Level.java
│ │ └── AndroidManifest.xml
└── build.gradle
├── fastlane
└── metadata
│ └── android
│ ├── en-US
│ ├── title.txt
│ ├── changelogs
│ │ ├── 18.txt
│ │ ├── 30.txt
│ │ ├── 19.txt
│ │ ├── 20.txt
│ │ ├── 15.txt
│ │ ├── 23.txt
│ │ ├── 26.txt
│ │ ├── 27.txt
│ │ ├── 24.txt
│ │ ├── 32.txt
│ │ ├── 13.txt
│ │ ├── 14.txt
│ │ ├── 17.txt
│ │ ├── 31.txt
│ │ ├── 25.txt
│ │ ├── 29.txt
│ │ ├── 16.txt
│ │ ├── 11.txt
│ │ ├── 21.txt
│ │ ├── 22.txt
│ │ ├── 28.txt
│ │ ├── 12.txt
│ │ └── 10.txt
│ ├── short_description.txt
│ ├── images
│ │ ├── icon.png
│ │ └── phoneScreenshots
│ │ │ ├── Bubble1.png
│ │ │ ├── Bubble2.png
│ │ │ └── Bubble3.png
│ └── full_description.txt
│ ├── ru
│ ├── title.txt
│ ├── short_description.txt
│ └── full_description.txt
│ ├── tr-TR
│ ├── title.txt
│ ├── short_description.txt
│ └── full_description.txt
│ └── de-DE
│ ├── title.txt
│ ├── changelogs
│ ├── 18.txt
│ ├── 19.txt
│ ├── 20.txt
│ ├── 26.txt
│ ├── 27.txt
│ ├── 30.txt
│ ├── 15.txt
│ ├── 23.txt
│ ├── 24.txt
│ ├── 32.txt
│ ├── 13.txt
│ ├── 17.txt
│ ├── 31.txt
│ ├── 16.txt
│ ├── 29.txt
│ ├── 25.txt
│ ├── 14.txt
│ ├── 21.txt
│ ├── 11.txt
│ ├── 22.txt
│ ├── 28.txt
│ ├── 12.txt
│ └── 10.txt
│ ├── short_description.txt
│ └── full_description.txt
├── settings.gradle
├── ic_launcher.odg
├── .gitattributes
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── .editorconfig
├── gradle.properties
├── .gitignore
├── gradlew.bat
├── ic_bubble.svg
├── ic_coarse.svg
├── README.md
├── ic_launcher_monochrome.svg
├── ic_launcher_foreground.svg
├── gradlew
└── ic_fine.svg
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -dontobfuscate
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/title.txt:
--------------------------------------------------------------------------------
1 | Bubble
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/ru/title.txt:
--------------------------------------------------------------------------------
1 | Пузырёк
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/tr-TR/title.txt:
--------------------------------------------------------------------------------
1 | Bubble
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/title.txt:
--------------------------------------------------------------------------------
1 | Wasserwaage
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/18.txt:
--------------------------------------------------------------------------------
1 | Bugfix
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/30.txt:
--------------------------------------------------------------------------------
1 | Bugfixes
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/18.txt:
--------------------------------------------------------------------------------
1 | Fehlerbehebung
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/19.txt:
--------------------------------------------------------------------------------
1 | GUI verbessert
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/20.txt:
--------------------------------------------------------------------------------
1 | GUI verbessert
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/26.txt:
--------------------------------------------------------------------------------
1 | GUI verbessert
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/27.txt:
--------------------------------------------------------------------------------
1 | GUI verbessert
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/30.txt:
--------------------------------------------------------------------------------
1 | Fehlerbehebung
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/19.txt:
--------------------------------------------------------------------------------
1 | Improved GUI
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/20.txt:
--------------------------------------------------------------------------------
1 | Improved GUI
2 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "Level"
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/15.txt:
--------------------------------------------------------------------------------
1 | Menü-Icons geändert
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/15.txt:
--------------------------------------------------------------------------------
1 | Changed menu icons
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/23.txt:
--------------------------------------------------------------------------------
1 | New feature: ruler
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/26.txt:
--------------------------------------------------------------------------------
1 | GUI improvements
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/27.txt:
--------------------------------------------------------------------------------
1 | GUI improvement
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/23.txt:
--------------------------------------------------------------------------------
1 | Neue Funktion: Lineal
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/24.txt:
--------------------------------------------------------------------------------
1 | Kalibrierung für Lineal
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/32.txt:
--------------------------------------------------------------------------------
1 | Show deprecation warning
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/24.txt:
--------------------------------------------------------------------------------
1 | Calibration for ruler
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/32.txt:
--------------------------------------------------------------------------------
1 | Show deprecation warning
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/tr-TR/short_description.txt:
--------------------------------------------------------------------------------
1 | Su terazisi ve cetvel
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/13.txt:
--------------------------------------------------------------------------------
1 | Leichte Glättung der Anzeigewerte
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/17.txt:
--------------------------------------------------------------------------------
1 | Upgrade auf Android 12 SDK
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/31.txt:
--------------------------------------------------------------------------------
1 | Android 15 Support (SDK 35)
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/short_description.txt:
--------------------------------------------------------------------------------
1 | Wasserwaage und Lineal
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/13.txt:
--------------------------------------------------------------------------------
1 | Slight averaging of display values
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/14.txt:
--------------------------------------------------------------------------------
1 | Added arrows for better alignment
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/17.txt:
--------------------------------------------------------------------------------
1 | Upgrade to Android 12 SDK
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/31.txt:
--------------------------------------------------------------------------------
1 | Android 15 Support (SDK 35)
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/short_description.txt:
--------------------------------------------------------------------------------
1 | Spirit level and ruler
2 |
--------------------------------------------------------------------------------
/ic_launcher.odg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/ic_launcher.odg
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/16.txt:
--------------------------------------------------------------------------------
1 | Bugfix: Steigung falsch berechnet
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/29.txt:
--------------------------------------------------------------------------------
1 | Reset für Kalibrierung des Lineals
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/25.txt:
--------------------------------------------------------------------------------
1 | Improved calibration for ruler
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/29.txt:
--------------------------------------------------------------------------------
1 | Reset button for ruler calibration
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/ru/short_description.txt:
--------------------------------------------------------------------------------
1 | Инструмент уровня (ватерпас) и линейка
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/25.txt:
--------------------------------------------------------------------------------
1 | Verbesserte Kalibrierung für Lineal
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/14.txt:
--------------------------------------------------------------------------------
1 | Pfeile für einfachere Aussrichtung hinzugefügt
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/16.txt:
--------------------------------------------------------------------------------
1 | Bugfix: wrong calculation of inclination
2 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/11.txt:
--------------------------------------------------------------------------------
1 | Modified options menu
2 | Added link to GitHub
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/21.txt:
--------------------------------------------------------------------------------
1 | Norwegian translation
2 | Monochrome icon support
3 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/bip.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/raw/bip.ogg
--------------------------------------------------------------------------------
/app/src/main/assets/fonts/lcd.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/assets/fonts/lcd.ttf
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/21.txt:
--------------------------------------------------------------------------------
1 | Norwegische Übersetzung
2 | Unterstützung für monochromes Icon
3 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/22.txt:
--------------------------------------------------------------------------------
1 | Norwegian translation
2 | New icon
3 | Monochrome icon support
4 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/11.txt:
--------------------------------------------------------------------------------
1 | Optionsmenü geändert
2 | Link zu GitHub hinzugefügt
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/ic_launcher-playstore.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/22.txt:
--------------------------------------------------------------------------------
1 | Norwegische Übersetzung
2 | Neues Icon
3 | Unterstützung für monochromes Icon
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/28.txt:
--------------------------------------------------------------------------------
1 | Android 14 support (SDK 34)
2 | Simplified color scheme
3 | Greek translation
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_fine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-hdpi/ic_fine.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldpi/ic_fine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-ldpi/ic_fine.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_fine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-mdpi/ic_fine.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_fine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-xhdpi/ic_fine.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/28.txt:
--------------------------------------------------------------------------------
1 | Android 14 Support (SDK 34)
2 | Vereinfachtes Farbschema
3 | Griechische Übersetzung
4 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_coarse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-hdpi/ic_coarse.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldpi/ic_coarse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-ldpi/ic_coarse.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_coarse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-mdpi/ic_coarse.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_coarse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-xhdpi/ic_coarse.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_fine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-xxhdpi/ic_fine.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_coarse.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable-xxhdpi/ic_coarse.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/fastlane/metadata/android/en-US/images/icon.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/12.txt:
--------------------------------------------------------------------------------
1 | Migrate to AppCompat and DayNight Theme
2 | Migrate to AndroidX
3 | Replace deprecated APIs
4 | Remove unused code
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_height_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/app/src/main/res/drawable/baseline_height_black_24dp.png
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | insert_final_newline = true
8 | trim_trailing_whitespace = true
9 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/12.txt:
--------------------------------------------------------------------------------
1 | Auf AppCompat und DayNight Theme umgestellt
2 | Auf AndroidX umgestellt
3 | Veraltete APIs ersetzt
4 | Ungenutzter Code entfernt
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #53537B
4 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/Bubble1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/Bubble1.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/Bubble2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/Bubble2.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/images/phoneScreenshots/Bubble3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woheller69/Level/HEAD/fastlane/metadata/android/en-US/images/phoneScreenshots/Bubble3.png
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/changelogs/10.txt:
--------------------------------------------------------------------------------
1 | Based on the source tar ball from F-Droid.
2 | Updated to targetSDK 30.
3 | Removed some unnecessary options.
4 | Minor layout changes.
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/changelogs/10.txt:
--------------------------------------------------------------------------------
1 | Basierend auf dem Source tar-Ball von F-Droid.
2 | Aktualisiert auf targetSDK 30.
3 | Einige unnötige Optionen entfernt.
4 | Geringe Layoutänderungen.
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 500
6 |
7 |
8 | 60
9 |
10 |
11 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/ru/full_description.txt:
--------------------------------------------------------------------------------
1 | С помощью Пузырька вы можете измерять углы и наклон.
2 |
3 | Просто совместите одну из четырех сторон вашего телефона с объектом или положите его на ровную поверхность чтобы определить его ориентацию.
4 |
5 | Также доступна линейка в сантиметрах и дюймах.
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/marker_2d.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/en-US/full_description.txt:
--------------------------------------------------------------------------------
1 | With Bubble you can measure angles and inclination.
2 |
3 | Simply align one of your phone's four sides with an object or place it on a level surface to determine its orientation.
4 |
5 | A ruler in cm and inches is also available.
6 |
7 | Experience a user-friendly and ad-free solution with no permissions required.
8 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/tr-TR/full_description.txt:
--------------------------------------------------------------------------------
1 | Bubble ile açıları ve eğimi ölçebilirsiniz.
2 |
3 | Yönünü belirlemek için telefonunuzun dört kenarından birini bir nesneyle hizalamanız veya düz bir yüzeye yerleştirmeniz yeterlidir.
4 |
5 | Ayrıca cm ve inç cinsinden bir cetvel de mevcuttur.
6 |
7 | İzin gerektirmeyen, kullanıcı dostu ve reklamsız bir çözümü deneyimleyin.
8 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/LevelApp.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level;
2 |
3 | import android.app.Application;
4 |
5 | import org.woheller69.level.util.PreferenceHelper;
6 |
7 | public class LevelApp extends Application {
8 |
9 | @Override
10 | public void onCreate() {
11 | super.onCreate();
12 | PreferenceHelper.initPrefs(this);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/fastlane/metadata/android/de-DE/full_description.txt:
--------------------------------------------------------------------------------
1 | Mit Bubble können Sie Winkel und Neigungen messen.
2 |
3 | Richten Sie einfach eine der vier Seiten Ihres Telefons an einem Objekt aus oder legen Sie es auf eine ebene Oberfläche, um seine Ausrichtung zu bestimmen.
4 |
5 | Ein Lineal in cm und inch ist ebenfalls verfügbar.
6 |
7 | Erleben Sie eine benutzerfreundliche und werbefreie Lösung, die keine Berechtigungen erfordert.
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/marker_1d.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/bubble.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
6 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_ruler.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_reset.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_calibrate.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/settings_activity.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
9 |
10 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/display.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
11 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
11 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 5dip
5 | 0dip
6 |
7 | 6dip
8 | 1dip
9 | 10dip
10 |
11 | 5dip
12 |
13 | 3dip
14 |
15 | 2dip
16 |
17 | 32dip
18 |
19 | 32dip
20 |
21 | 12dip
22 | 10dip
23 |
24 |
--------------------------------------------------------------------------------
/app/src/main/res/values/pref_arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - @string/angle
6 | - @string/inclination
7 |
8 |
9 | - @string/prefKey_displayType_angle
10 | - @string/prefKey_displayType_inclination
11 |
12 |
13 |
14 | - @string/viscosity_low
15 | - @string/viscosity_medium
16 | - @string/viscosity_high
17 |
18 |
19 | - @string/prefKey_viscosity_low
20 | - @string/prefKey_viscosity_medium
21 | - @string/prefKey_viscosity_high
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
30 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/util/PrefKeys.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.util;
2 |
3 | import org.woheller69.level.R;
4 |
5 | public class PrefKeys {
6 | public static final int PREF_SHOW_ANGLE = R.string.prefKey_showAngle;
7 |
8 | public static final int PREF_DISPLAY_TYPE = R.string.prefKey_displayType;
9 | public static final int PREF_DISPLAY_TYPE_ANGLE = R.string.prefKey_displayType_angle;
10 | public static final int PREF_DISPLAY_TYPE_INCLINATION = R.string.prefKey_displayType_inclination;
11 |
12 | public static final int PREF_LOCK_ORIENTATION = R.string.prefKey_lockOrientation;
13 |
14 | public static final int PREF_VISCOSITY = R.string.prefKey_viscosity;
15 | public static final int PREF_VISCOSITY_LOW = R.string.prefKey_viscosity_low;
16 | public static final int PREF_VISCOSITY_MEDIUM = R.string.prefKey_viscosity_medium;
17 | public static final int PREF_VISCOSITY_HIGH = R.string.prefKey_viscosity_high;
18 |
19 | public static final int PREF_ENABLE_SOUND = R.string.prefKey_enableSound;
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/res/values/pref_keys.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | pref_showAngle
5 |
6 | pref_displayType
7 | pref_displayType_angle
8 | pref_displayType_inclination
9 |
10 | pref_lockOrientation
11 |
12 | pref_viscosity
13 | pref_viscosity_low
14 | pref_viscosity_medium
15 | pref_viscosity_high
16 |
17 | pref_enableSound
18 |
19 |
20 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/orientation/OrientationListener.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.orientation;
2 |
3 | /*
4 | * This file is part of Level (an Android Bubble Level).
5 | *
6 | *
7 | * Copyright (C) 2014 Antoine Vianey
8 | *
9 | * Level is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * Level is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU General Public License
20 | * along with Level. If not, see
21 | */
22 | public interface OrientationListener {
23 |
24 | void onOrientationChanged(Orientation orientation, float pitch, float roll, float balance);
25 |
26 | void onCalibrationSaved(boolean success);
27 |
28 | void onCalibrationReset(boolean success);
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/level_1d.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
11 |
16 |
17 |
18 | -
19 |
20 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-nodpi/level_2d.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | -
4 |
5 |
12 |
17 |
18 |
19 | -
20 |
21 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
10 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.aar
4 | *.ap_
5 | *.aab
6 |
7 | # Files for the ART/Dalvik VM
8 | *.dex
9 |
10 | # Java class files
11 | *.class
12 |
13 | # Generated files
14 | bin/
15 | gen/
16 | out/
17 | app/debug/
18 | app/release/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/
42 |
43 | # Keystore files
44 | # Uncomment the following lines if you do not want to check your keystore files in.
45 | #*.jks
46 | #*.keystore
47 |
48 | # External native build folder generated in Android Studio 2.2 and later
49 | .externalNativeBuild
50 | .cxx/
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | # google-services.json
54 |
55 | # Freeline
56 | freeline.py
57 | freeline/
58 | freeline_project_description.json
59 |
60 | # fastlane
61 | fastlane/report.xml
62 | fastlane/Preview.html
63 | fastlane/screenshots
64 | fastlane/test_output
65 | fastlane/readme.md
66 |
67 | # Version control
68 | vcs.xml
69 |
70 | # lint
71 | lint/intermediates/
72 | lint/generated/
73 | lint/outputs/
74 | lint/tmp/
75 | # lint/reports/
76 | /app/release/output-metadata.json
77 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 |
5 | android {
6 | compileSdk 35
7 | namespace 'org.woheller69.level'
8 | android.buildFeatures.buildConfig true
9 | defaultConfig {
10 | applicationId "org.woheller69.level"
11 | minSdk 16
12 | targetSdk 35
13 | versionCode 32
14 | versionName "3.2"
15 | vectorDrawables.useSupportLibrary true
16 | }
17 |
18 | buildTypes {
19 | release {
20 | minifyEnabled true
21 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
22 | }
23 | }
24 |
25 | compileOptions {
26 | encoding "UTF-8"
27 | sourceCompatibility JavaVersion.VERSION_1_8
28 | targetCompatibility JavaVersion.VERSION_1_8
29 | }
30 |
31 | lintOptions {
32 | disable 'GoogleAppIndexingWarning'
33 | }
34 |
35 | packagingOptions {
36 | exclude 'META-INF/*'
37 | }
38 | }
39 |
40 | dependencies {
41 | implementation "androidx.appcompat:appcompat:1.6.1"
42 | implementation "androidx.preference:preference:1.2.1"
43 | implementation "androidx.lifecycle:lifecycle-viewmodel:2.5.1" //needed due to duplicate class error
44 | implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1" //needed due to duplicate class error
45 | implementation 'com.github.woheller69:FreeDroidWarn:V1.3'
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #FF000000
5 | #FFFFFFFF
6 | #FF888888
7 | #EE53537B
8 | #FFB1C800
9 | #00FFFFFF
10 | #44FFFFFF
11 |
12 |
13 | @color/green
14 | @color/black
15 | @color/green
16 | @color/black
17 |
18 | @color/black
19 | @color/black
20 | @color/black
21 |
22 | @color/violet
23 |
24 |
25 | @color/green
26 | @color/semitranslucent
27 |
28 | @color/green
29 | @color/semitranslucent
30 |
31 | @color/black
32 | @color/black
33 | @color/black
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/SettingsFragment.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.preference.ListPreference;
6 | import androidx.preference.PreferenceFragmentCompat;
7 |
8 | import org.woheller69.level.util.PrefKeys;
9 | import org.woheller69.level.util.PreferenceHelper;
10 |
11 | public class SettingsFragment extends PreferenceFragmentCompat {
12 | @Override
13 | public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
14 | addPreferencesFromResource(R.xml.preferences);
15 |
16 | final ListPreference displayType = findPreference(getString(PrefKeys.PREF_DISPLAY_TYPE));
17 | if (displayType != null) {
18 | displayType.setSummaryProvider(preference -> {
19 | if (PreferenceHelper.isDisplayTypeInclination()) {
20 | return getString(R.string.inclination_summary);
21 | }
22 | // default display type
23 | return getString(R.string.angle_summary);
24 | });
25 | }
26 |
27 | final ListPreference viscosity = findPreference(getString(PrefKeys.PREF_VISCOSITY));
28 | if (viscosity != null) {
29 | viscosity.setSummaryProvider(preference -> {
30 | if (PreferenceHelper.isViscosityLow()) {
31 | return getString(R.string.viscosity_low_summary);
32 | }
33 | if (PreferenceHelper.isViscosityHigh()) {
34 | return getString(R.string.viscosity_high_summary);
35 | }
36 | // default viscosity
37 | return getString(R.string.viscosity_medium_summary);
38 | });
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 水准仪
4 | 重置
5 | 不支持定向
6 | 校准
7 | 点击菜单按钮校准...
8 | 校准手机
9 | 将手机调整至水平位置,点击校准按钮。
10 |
11 | 或重置校准手机的所有边。
12 | 定制校准已保存!
13 | 校准失败!
14 | 初始校准已恢复!
15 | 设置
16 | 多角度显示
17 | 在界面上显示角度值
18 | 显示类型
19 | 音效
20 | 测量时播放声音
21 | 锁定
22 | 允许方位锁定
23 | 粘度
24 | 角度
25 | 点击锁定方位
26 | 倾斜度
27 | 角度
28 | "倾斜度:
29 | 100% ~ 45°"
30 | 低
31 | 中
32 | 高
33 | "低粘度
34 | 气泡快速移动"
35 | "中粘度
36 | 气泡常速移动"
37 | "高粘度
38 | 气泡慢速移动"
39 | Toggle mode
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh-rCN/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 水准仪
4 | 重置
5 | 不支持定向
6 | 校准
7 | 点击菜单按钮校准...
8 | 校准手机
9 | 将手机调整至水平位置,点击校准按钮。
10 |
11 | 或重置校准手机的所有边。
12 | 定制校准已保存!
13 | 校准失败!
14 | 初始校准已恢复!
15 | 设置
16 | 多角度显示
17 | 在界面上显示角度值
18 | 显示类型
19 | 音效
20 | 测量时播放声音
21 | 锁定
22 | 允许方位锁定
23 | 粘度
24 | 角度
25 | 点击锁定方位
26 | 倾斜度
27 | 角度
28 | "倾斜度:
29 | 100% ~ 45°"
30 | 低
31 | 中
32 | 高
33 | "低粘度
34 | 气泡快速移动"
35 | "中粘度
36 | 气泡常速移动"
37 | "高粘度
38 | 气泡慢速移动"
39 | Toggle mode
40 |
41 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_bubble.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
15 |
16 |
24 |
25 |
31 |
32 |
39 |
40 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/SettingsActivity.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level;
2 |
3 | import android.content.res.Configuration;
4 | import android.os.Build;
5 | import android.os.Bundle;
6 | import android.view.WindowInsetsController;
7 |
8 | import androidx.appcompat.app.ActionBar;
9 | import androidx.appcompat.app.AppCompatActivity;
10 |
11 | public class SettingsActivity extends AppCompatActivity {
12 |
13 | @Override
14 | protected void onCreate(Bundle savedInstanceState) {
15 | super.onCreate(savedInstanceState);
16 | setContentView(R.layout.settings_activity);
17 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
18 | int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
19 | boolean isDarkMode = (nightModeFlags == Configuration.UI_MODE_NIGHT_YES);
20 | WindowInsetsController insetsController = getWindow().getInsetsController();
21 | if (insetsController != null) {
22 | if (isDarkMode) {
23 | // Dark mode: remove light status bar appearance (use light icons)
24 | insetsController.setSystemBarsAppearance(
25 | 0,
26 | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
27 | );
28 | } else {
29 | // Light mode: enable light status bar appearance (dark icons)
30 | insetsController.setSystemBarsAppearance(
31 | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
32 | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
33 | );
34 | }
35 | }
36 | }
37 | if (savedInstanceState == null) {
38 | getSupportFragmentManager()
39 | .beginTransaction()
40 | .replace(R.id.settings_container, new SettingsFragment())
41 | .commit();
42 | }
43 | ActionBar actionBar = getSupportActionBar();
44 | if (actionBar != null) {
45 | actionBar.setDisplayHomeAsUpEnabled(true);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Reset
5 | Orientation not supported
6 | Calibrate
7 | press MENU to calibrate...
8 | Calibrate your phone
9 | Put any side (including the back) of your device on a flat horizontal surface and press the Calibrate button.\n\nOr reset the calibration for all the phone sides.
10 | Custom calibration saved !
11 | Calibration failed !
12 | Original calibration restored !
13 | Settings
14 | Show numeric angle
15 | Display angle value(s) on screen
16 | Display type
17 | Sound effects
18 | Play sound when level
19 | Locking
20 | Allow level orientation locking
21 | Viscosity
22 | Angle
23 | tap to lock level orientation
24 | Inclination
25 | Angle in degrees
26 | Inclination in percents\n100% ~ 45°
27 | Low
28 | Medium
29 | High
30 | Low viscosity\nBubble moves faster
31 | Medium viscosity\nBubble moves normally
32 | High viscosity\nBubble moves slowly
33 | Toggle mode
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt-rBR/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Reiniciar
5 | Orientação não suportada
6 | Calibrar
7 | Clique em MENU para calibrar...
8 | Calibrar o celular
9 | Coloque o lado do celular que deseja calibrar em uma superfície plana horizontal e clique em Calibrar.
10 | A calibragem foi salvada!
11 | A calibragem falhou!
12 | Calibragem de origem aplicada!
13 | Opções
14 | Mostrar o valor do ângulo
15 | Mostrar os valores na tela
16 | Tipo de informação
17 | Efeitos de som
18 | Reproduzir som quando estabiliza a medição
19 | Bloqueio
20 | Bloquear o tipo de nível usado
21 | Viscosidade
22 | Ângulo
23 | Clicar para bloquear neste sensor
24 | Inclinação
25 | Ângulo em graus
26 | Inclinação em porcentagem\n100% ~ 45°
27 | Baixa
28 | Média
29 | Alta
30 | Baixa viscosidade\nA bolha move-se mais rápido
31 | Média viscosidade\nA bolha move-se normal
32 | Alta viscosidade\nA bolha move-se mais lento
33 | Mudar o modo
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-es/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Nivel
4 | Inic.
5 | Orientación incompatibles
6 | Calibrar
7 | pulse MENU para calibrar...
8 | Calibrar el teléfono
9 | Pon el lado del teléfono que desea calibrar sobre una superficie plana horizontal y pulse el botón Calibrar.
10 | Calibración personalizada salvado !
11 | Error de calibración !
12 | Calibración original restaurada !
13 | Preferencias
14 | Mostrar el ángulo
15 | Pantalla de inclinación
16 | Tipo de pantalla
17 | Efectos sonoros
18 | Alarma sonora
19 | Orientación
20 | Conservar la orientación del nivel
21 | Viscosidad
22 | Angulo
23 | hundir para conservar la orientación
24 | Inclinación
25 | Ángulo en grados
26 | Inclinación en porcentajes\n100% ~ 45°
27 | Baja
28 | Media
29 | Alta
30 | Baja viscosidad\nEl burbuja se mueve rápidamente
31 | Viscosidad media\nEl burbuja se mueve a velocidad normal
32 | Alta viscosidad\nEl burbuja se mueve lentamente
33 | Cambiar el modo
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nl/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Reset
5 | Oriëntatie wordt niet ondersteund
6 | Calibreren
7 | Druk op MENU voor calibratie
8 | Calibreer uw telefoon
9 | Plaats de zijkant van de telefoon die u wilt kalibreren op een vlak horizontaal oppervlak en druk op Calibreren
10 | Nieuwe calibratie opgeslagen !
11 | Calibratie mislukt !
12 | Oorspronkelijke calibratie hersteld !
13 | Opties
14 | Toon Hoek
15 | Geef de waarde(s) van de hoek weer
16 | Weergave type
17 | Geluidseffecten
18 | Speel geluid af als het toestel horizontaal ligt
19 | Vergrendeling
20 | Sta oriëntatie-niveau vergrendeling toe
21 | Viscositeit
22 | Hoek
23 | tik hier om de hoek te vergrendelan
24 | Helling
25 | Hoek in graden
26 | Helling in procenten\n100% ~ 45°
27 | Laag
28 | Middelmatig
29 | Hoog
30 | Lage viscositeit\nLuchtbel beweegt snel
31 | Middelmatige viscositeit\nLuchtbel beweegt normaal
32 | Hoge viscositeit\nLuchtbel beweegt traag
33 | Toggle mode
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-pt/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Reiniciar
5 | Orientatação não suportada
6 | Calibrar
7 | Clique em MENU para calibrar...
8 | Calibrar o telemóvel
9 | Coloque o lado do telefone que deseja calibrar numa superfície plana horizontal e clique em Calibrar.
10 | A calibragem foi guardada!
11 | A calibragem falhou!
12 | Aplicada a calibragem de origem!
13 | Opções
14 | Mostrar o valor do ângulo
15 | Mostrar os valores no ecrâ
16 | Tipo de informação
17 | Efeitos de som
18 | Reproduzir som quando a medição estabilizar
19 | Bloqueio
20 | Bloquear o tipo de nível a usar
21 | Viscosidade
22 | Ângulo
23 | Clicar para bloquear neste sensor
24 | Inclinação
25 | Ângulo em graus
26 | Inclinação em percentagem\n100% ~ 45°
27 | Baixa
28 | Média
29 | Alta
30 | Baixa viscosidade\nA bolha move-se mais rápidamente
31 | Média viscosidade\nA bolha move-se a uma velocidade normal
32 | Alta viscosidade\nA bolha move-se mais lentamente
33 | Mudar o modo
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-cs/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Resetovat
5 | Orientace není podporována
6 | Kalibrovat
7 | pro kalibraci ťukni na MENU...
8 | Kalibrovat telefon
9 | Položte libovolnou stranu (včetně zadní) zařízení Android na rovný vodorovný povrch a stiskněte tlačítko Kalibrovat.\n\nNebo resetujte kalibraci všech stran telefonu.
10 | Vlastní kalibrace uložena!
11 | Kalibrace selhala!
12 | Výchozí kalibrace obnovena!
13 | Nastavení
14 | Zobrazit úhel
15 | Zobrazovat hodnotu(y) úhlu na obrazovce
16 | Typ zobrazení
17 | Zvukové efekty
18 | Přehrát zvuk při vyrovnání
19 | Zamykání
20 | Povolit uzamknutí změny orientace
21 | Viskozita
22 | Úhel
23 | ťukněte pro uzamčení změny orientace
24 | Sklon
25 | Úhel ve stupních
26 | Sklon v procentech\n100% ~ 45°
27 | Nízká
28 | Střední
29 | Vysoká
30 | Nízká viskozita\nBulina se pohybuje rychleji
31 | Střední viskozita\nBulina se pohybuje středně rychle
32 | Vysoká viskozita\nBulina se pohybuje pomaleji
33 | Toggle mode
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-nb/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Tilbakestill
5 | Orientering ikke støttet
6 | Kalibrer
7 | trykk MENY for å kalibrere...
8 | Kalibrer telefonen
9 | Legg hvilken som helst side (inkludert baksiden) av enheten din på en flat horisontal overflate og trykk knappen Kalibrer.\n\nEller tilbakestill kalibreringen for alle sidene av telefonen.
10 | Kalibrering lagret!
11 | Kalibrering feilet!
12 | Opprinnelig kalibrering gjenopprettet!
13 | Innstillinger
14 | Vis numerisk vinkel
15 | Vis vinkelverdi(er) på skjermen
16 | Visningstype
17 | Lydeffekter
18 | Avspill lyd når i vater
19 | Låsing
20 | Tillat låsing av vaterorientering
21 | Viskositet
22 | Vinkel
23 | trykk for å låse vaterorientering
24 | Helling
25 | Vinkel i grader
26 | Helling i prosent\n100% ~ 45°
27 | Lav
28 | Middels
29 | Høy
30 | Lav viskositet\nLuftboble beveger seg raskere
31 | Middels viskositet\nLuftboble beveger seg normalt
32 | Høy viskositet\nLuftboble beveger seg sakte
33 | Skift modus
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-it/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Livella
4 | Reset
5 | Orientamento non supportato
6 | Calibrare
7 | Premere MENU per calibrare...
8 | Calibrare il telefono
9 | Posto il lato del telefono che si desidera calibrare su una superficie piana orizzontale e premere il pulsante di calibrazione.
10 | Calibrazione personalizzata salvata !
11 | La calibrazione fallito !
12 | Calibrazione originale restaurata !
13 | Preferenze
14 | Mostra digitale
15 | Visualizzazione del valore di angolo
16 | Tipo di display
17 | Effetti sonori
18 | Riproduci suono quando il livello
19 | Orientamento
20 | Preserva il orientamento di livello
21 | Viscosità
22 | Angolo
23 | premere per bloccare il orientamento
24 | Inclinazione
25 | Angolo in gradi
26 | Inclinazione in percentuale\n100% ~ 45°
27 | Bassa
28 | Media
29 | Alta
30 | Bassa viscosità\nLa bolla si muove rapidamente
31 | Media viscosità\nLa bolla si muove a velocità normale
32 | Alta viscosità\nLa bolla si muove lentamente
33 | Cambiare la modalità
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-de/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Zurücksetzen
5 | Ausrichtung nicht unterstützt
6 | Kalibrieren
7 | Drücke MENU zum Kalibrieren...
8 | Das Gerät kalibrieren
9 | Lege die Seite des Telefons zum Kalibrieren auf eine flache horizontale Oberfläche und drücke die Schaltfläche Kalibrieren.
10 | Kalibrierung erfolgreich!
11 | Kalibrierung fehlgeschlagen!
12 | Originale Kalibrierung wiederhergestellt!
13 | Einstellungen
14 | Zeige numerischen Winkel
15 | Zeige den Wert als Zahl auf dem Bildschirm
16 | Anzeigewert
17 | Soundeffekte
18 | Spiele einen Sound, wenn in der Waage
19 | Sperren
20 | Erlaube das Sperren der Ausrichtung
21 | Viskosität
22 | Winkel
23 | Berühren um die Ausrichtung zu sperren
24 | Steigung
25 | Winkel in Grad
26 | Steigung in Prozent\n100% ~ 45°
27 | Gering
28 | Mittel
29 | Hoch
30 | Geringe Viskosität\nLuftblase bewegt sich schneller
31 | Mittlere Viskosität\nLuftblase bewegt sich normal
32 | Hohe Viskosität\nLuftblase bewegt sich langsam
33 | Modus umschalten
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Sıfırla
5 | Yönlendirme desteklenmiyor
6 | Kalibre et
7 | kalibre etmek için MENÜ\'ye basın...
8 | Telefonunuzu kalibre edin
9 | Android cihazınızın herhangi bir tarafını (arkası dahil) düz yatay bir yüzeye koyun ve Kalibre Et düğmesine basın.\n\nYa da tüm telefon tarafları için kalibrasyonu sıfırlayın.
10 | Özel kalibrasyon kaydedildi!
11 | Kalibrasyon başarısız oldu!
12 | Orijinal kalibre geri yüklendi!
13 | Ayarlar
14 | Sayısal açıyı göster
15 | Açı değer(ler)ini ekranda görüntüle
16 | Ekran tipi
17 | Ses efektleri
18 | Seviye geldiğinde ses çal
19 | Kilitleniyor
20 | Seviye yönünü kilitlemesine izin ver
21 | Viskozite
22 | Açı
23 | seviye yönünü kilitlemek için dokunun
24 | Eğim
25 | Derece cinsinden açı
26 | Yüzde cinsinden eğim\n100% ~ 45°
27 | Düşük
28 | Orta
29 | Yüksek
30 | Düşük viskozite\nKabarcık daha hızlı hareket eder
31 | Orta viskozite\nKabarcık normal hareket eder
32 | Yüksek viskozite\nKabarcık yavaş hareket eder
33 | Modu değiştir
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Пузырёк
4 | Сброс
5 | Ориентация не поддерживается
6 | Калибровка
7 | нажмите МЕНЮ для калибровки...
8 | Откалибруйте свой телефон
9 | Положите любую сторону (включая заднюю) вашего устройства на плоскую горизонтальную поверхность и нажмите кнопку Калибровать.\n\nНе сбрасывайте калибровку для всех сторон телефона.
10 | Своя калибровка сохранена!
11 | Ошибка калибровки!
12 | Первоначальная калибровка восстановлена!
13 | Настройки
14 | Показывать числовой угол
15 | Отображать значения углов на экране
16 | Тип отображения
17 | Звуковые эффекты
18 | Воспроизводить звук при достижении уровня
19 | Фиксация
20 | Разрешить фиксацию ориентации уровня
21 | Вязкость
22 | Угол
23 | Нажмите чтобы зафиксировать ориентацию уровня
24 | Наклон
25 | Угол в градусах
26 | Наклон в процентах\n100% ~ 45°
27 | Низкая
28 | Средняя
29 | Высокая
30 | Низкая вязкость\nПузырёк движется быстрее
31 | Средняя вязкость\nПузырёк движется нормально
32 | Высокая вязкость\nПузырёк движется медленно
33 | Toggle mode
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/orientation/Orientation.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.orientation;
2 |
3 | /*
4 | * This file is part of Level (an Android Bubble Level).
5 | *
6 | *
7 | * Copyright (C) 2014 Antoine Vianey
8 | *
9 | * Level is free software: you can redistribute it and/or modify
10 | * it under the terms of the GNU General Public License as published by
11 | * the Free Software Foundation, either version 3 of the License, or
12 | * (at your option) any later version.
13 | *
14 | * Level is distributed in the hope that it will be useful,
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | * GNU General Public License for more details.
18 | *
19 | * You should have received a copy of the GNU General Public License
20 | * along with Level. If not, see
21 | */
22 | public enum Orientation {
23 |
24 | LANDING(1, 0),
25 | TOP(1, 0),
26 | RIGHT(1, 90),
27 | BOTTOM(-1, 180),
28 | LEFT(-1, -90);
29 |
30 | private int reverse;
31 | private int rotation;
32 |
33 | private Orientation(int reverse, int rotation) {
34 | this.reverse = reverse;
35 | this.rotation = rotation;
36 | }
37 |
38 | public int getReverse() {
39 | return reverse;
40 | }
41 |
42 | public int getRotation() {
43 | return rotation;
44 | }
45 |
46 | public boolean isLevel(float pitch, float roll, float balance, float sensibility) {
47 | if (sensibility < 0.2f) {
48 | //minimum sensibility for playing sound (play sound even if sensor sensibility is better)
49 | sensibility = 0.2f;
50 | }
51 | switch (this) {
52 | case BOTTOM:
53 | case TOP:
54 | return balance <= sensibility
55 | && balance >= -sensibility;
56 | case LANDING:
57 | return roll <= sensibility
58 | && roll >= -sensibility
59 | && (Math.abs(pitch) <= sensibility
60 | || Math.abs(pitch) >= 180 - sensibility);
61 | case LEFT:
62 | case RIGHT:
63 | return Math.abs(pitch) <= sensibility
64 | || Math.abs(pitch) >= 180 - sensibility;
65 | }
66 | return false;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/app/src/main/res/values-fr/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Niveau
4 | Init.
5 | Orientation non supportée
6 | Etalonner
7 | appuyez sur MENU pour étalonner...
8 | Etalonnage du téléphone
9 | Posez le côté du téléphone que vous souhaitez calibrer sur une surface horizontale et plane de référence puis appuyez sur le bouton Etalonner.\n\nOu réinitialisez l\'étalonnage pour l\'ensemble des côtés du téléphone.
10 | Etalonnage sauvegardé !
11 | L\'étalonnage a échoué !
12 | Etalonnage d\'usine restauré !
13 | Préférences
14 | Affichage numérique
15 | Affiche la valeur de l\'inclinaison
16 | Type d\'affichage
17 | Effets sonores
18 | Joue un son à l\'équilibre
19 | Verrouillage
20 | Verrouille l\'orientation du niveau
21 | Viscosité
22 | Angle
23 | appuyer pour verrouiller l\'orientation
24 | Pente
25 | Angle en degrés
26 | Pente en pourcents\n100% ~ 45°
27 | Faible
28 | Moyenne
29 | Elevée
30 | Faible viscosité\nLa bulle se déplace rapidement
31 | Viscosité moyenne\nLa bulle se déplace a vitesse normal
32 | Viscosité élevée\nLa bulle se déplace lentement
33 | Changer de mode
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_coarse.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
12 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-eu/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Bubble
4 | Berrezarri
5 | Orientazioa ez da onartzen
6 | Kalibratu
7 | sakatu MENU kalibratzeko...
8 | Kalibratu zure telefonoa
9 | Jarri zure Android gailuaren edozein alde (atzekoa barne) gainazal horizontal lau batean eta sakatu Kalibratu botoia.\n\nEdo berrezarri kalibrazioa telefonoaren alde guztientzat.
10 | Kalibrazio pertsonalizatua gordeta!
11 | Kalibrazioak huts egind du!
12 | Jatorrizko kalibrazioa leheneratuta!
13 | Ezarpenak
14 | Erakutsi zenbakizko angelua
15 | Bistaratu angeluaren balioa(k) pantailan
16 | Bistaratze mota
17 | Soinu-efektuak
18 | Erreproduzitu soinua nibelean dagoenean
19 | Blokeatzea
20 | Baimendu nibelaren orientazioa blokeatzea
21 | Biskositatea
22 | Angelua
23 | ukitu nibelaren orientazioa blokeatzeko
24 | Inklinazioa
25 | Angelua gradutan
26 | Inklinazioa ehunekotan\n100% ~ 45°
27 | Baxua
28 | Ertaina
29 | Altua
30 | Biskositate baxua\nBurbuila azkarrago mugitzen da
31 | Biskositate ertaina\nBurbuila normal mugitzen da
32 | Biskositate altua\nBurbuila mantso mugitzen da
33 | Toggle mode
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/values-el/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Φυσαλίδα
4 | Επαναφορά
5 | Ο προσανατολισμός δεν υποστηρίζεται
6 | Βαθμονόμηση
7 | Πατήστε ΜΕΝΟΥ για βαθμονόμηση...
8 | Βαθμονομήστε το τηλέφωνο
9 | Τοποθετήστε οποιαδήποτε πλευρά (συμπεριλαμβανομένης της πίσω) της συσκευής σας σε μια επίπεδη οριζόντια επιφάνεια και πατήστε το κουμπί Βαθμονόμηση.\n\nΉ επαναφέρετε τη βαθμονόμηση για όλες τις πλευρές του τηλεφώνου.
10 | Η προσαρμοσμένη βαθμονόμηση αποθηκεύτηκε!
11 | Η βαθμονόμηση απέτυχε!
12 | Επανήλθε η αρχική βαθμονόμηση
13 | Ρυθμίσεις
14 | Εμφάνιση αριθμητικής γωνίας
15 | Εμφάνιση τιμών γωνίας στην οθόνη
16 | Μορφή εμφάνισης
17 | Ηχητικά εφέ
18 | Αναπαραγωγή ήχου κατά την οριζοντίωση
19 | Κλείδωμα
20 | Να επιτρέπεται το κλείδωμα του αλφαδιού
21 | Ιξώδες
22 | Γωνία
23 | Πατήστε για να κλειδώσετε τον προσανατολισμό του αλφαδιού
24 | Κλίση
25 | Γωνία σε μοίρες
26 | Κλίση σε ποσοστό\n100% ~ 45°
27 | Χαμηλό
28 | Μεσαίο
29 | Υψηλό
30 | Χαμηλό ιξώδες\nΗ φυσαλίδα κινείται γρήγορα
31 | Μεσαίο ιξώδες\nΗ φυσαλίδα κινείται κανονικά
32 | Υψηλό ιξώδες\nΗ φυσαλίδα κινείται αργά
33 | Toggle mode
34 |
35 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_monochrome.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
12 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/view/LevelView.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.view;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Looper;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 | import android.view.SurfaceHolder;
9 | import android.view.SurfaceView;
10 | import android.view.View;
11 | import android.view.View.OnTouchListener;
12 |
13 | import org.woheller69.level.orientation.Orientation;
14 | import org.woheller69.level.painter.LevelPainter;
15 |
16 | /*
17 | * This file is part of Level (an Android Bubble Level).
18 | *
19 | *
20 | * Copyright (C) 2014 Antoine Vianey
21 | *
22 | * Level is free software: you can redistribute it and/or modify
23 | * it under the terms of the GNU General Public License as published by
24 | * the Free Software Foundation, either version 3 of the License, or
25 | * (at your option) any later version.
26 | *
27 | * Level is distributed in the hope that it will be useful,
28 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 | * GNU General Public License for more details.
31 | *
32 | * You should have received a copy of the GNU General Public License
33 | * along with Level. If not, see
34 | */
35 | public class LevelView extends SurfaceView implements SurfaceHolder.Callback, OnTouchListener {
36 |
37 | private LevelPainter painter;
38 |
39 | public LevelView(Context context, AttributeSet attrs) {
40 | super(context, attrs);
41 | getHolder().addCallback(this);
42 | setFocusable(true);
43 | setOnTouchListener(this);
44 | }
45 |
46 | @Override
47 | public void onWindowFocusChanged(boolean hasWindowFocus) {
48 | if (painter != null) {
49 | painter.pause(!hasWindowFocus);
50 | }
51 | }
52 |
53 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
54 | if (painter != null) {
55 | painter.setSurfaceSize(width, height);
56 | }
57 | }
58 |
59 | public void surfaceCreated(SurfaceHolder holder) {
60 | if (painter == null) {
61 | painter = new LevelPainter(holder, getContext(), new Handler(Looper.getMainLooper()));
62 | }
63 | }
64 |
65 | public void surfaceDestroyed(SurfaceHolder holder) {
66 | if (painter != null) {
67 | painter.pause(true);
68 | painter.clean();
69 | painter = null;
70 | }
71 | // free resources
72 | System.gc();
73 | }
74 |
75 | public void onOrientationChanged(Orientation orientation, float pitch, float roll, float balance) {
76 | if (painter != null) {
77 | painter.onOrientationChanged(orientation, pitch, roll, balance);
78 | }
79 | }
80 |
81 | @Override
82 | public boolean onTouch(View v, MotionEvent event) {
83 | if (event.getAction() == MotionEvent.ACTION_DOWN && painter != null) {
84 | painter.onTouch((int) event.getX(), (int) event.getY());
85 | }
86 | return true;
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/view/VerticalSeekBar.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.view;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.graphics.Canvas;
6 | import android.util.AttributeSet;
7 | import android.view.MotionEvent;
8 |
9 | import androidx.appcompat.widget.AppCompatSeekBar;
10 |
11 |
12 | public class VerticalSeekBar extends AppCompatSeekBar {
13 | private static final int ROTATION_ANGLE = -90;
14 |
15 | private OnSeekBarChangeListener mOnSeekBarChangeListener;
16 |
17 | public VerticalSeekBar(final Context context) {
18 | super(context);
19 | }
20 |
21 | public VerticalSeekBar(final Context context, final AttributeSet attrs, final int defStyle) {
22 | super(context, attrs, defStyle);
23 | }
24 |
25 | public VerticalSeekBar(final Context context, final AttributeSet attrs) {
26 | super(context, attrs);
27 | }
28 |
29 | @Override
30 | protected final void onSizeChanged(final int width, final int height, final int oldWidth, final int oldHeight) {
31 | super.onSizeChanged(height, width, oldHeight, oldWidth);
32 | }
33 |
34 | @Override
35 | protected final synchronized void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
36 | super.onMeasure(heightMeasureSpec, widthMeasureSpec);
37 | setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
38 | }
39 |
40 | @Override
41 | protected final void onDraw(final Canvas c) {
42 | c.rotate(ROTATION_ANGLE);
43 | c.translate(-getHeight(), 0);
44 |
45 | super.onDraw(c);
46 | }
47 |
48 | @Override
49 | public final void setOnSeekBarChangeListener(final OnSeekBarChangeListener l) {
50 | mOnSeekBarChangeListener = l;
51 | super.setOnSeekBarChangeListener(l);
52 | }
53 |
54 | @SuppressLint("ClickableViewAccessibility")
55 | @Override
56 | public final boolean onTouchEvent(final MotionEvent event) {
57 | if (!isEnabled()) {
58 | return false;
59 | }
60 |
61 | switch (event.getAction()) {
62 | case MotionEvent.ACTION_DOWN:
63 | setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
64 | mOnSeekBarChangeListener.onStartTrackingTouch(this);
65 | break;
66 |
67 | case MotionEvent.ACTION_MOVE:
68 | setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
69 | break;
70 |
71 | case MotionEvent.ACTION_UP:
72 | setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
73 | mOnSeekBarChangeListener.onStopTrackingTouch(this);
74 | break;
75 |
76 | case MotionEvent.ACTION_CANCEL:
77 | mOnSeekBarChangeListener.onStopTrackingTouch(this);
78 | break;
79 |
80 | default:
81 | break;
82 | }
83 |
84 | return true;
85 | }
86 |
87 | @Override
88 | public final void setProgress(final int progress) {
89 | super.setProgress(progress);
90 | onSizeChanged(getWidth(), getHeight(), 0, 0);
91 | }
92 | }
93 |
94 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
34 |
41 |
48 |
55 |
56 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/util/PreferenceHelper.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.util;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.res.Resources;
6 |
7 | import androidx.annotation.StringRes;
8 | import androidx.preference.PreferenceManager;
9 |
10 | public class PreferenceHelper {
11 | private static SharedPreferences sharedPrefs;
12 | private static Resources mRes;
13 |
14 | public static void initPrefs(final Context context) {
15 | sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
16 | mRes = context.getResources();
17 | }
18 |
19 | private static String getPrefKey(@StringRes final int prefKey) {
20 | return mRes.getString(prefKey);
21 | }
22 |
23 | private static boolean getHelperBoolean(@StringRes final int prefKey, final boolean defValue) {
24 | return sharedPrefs.getBoolean(getPrefKey(prefKey), defValue);
25 | }
26 |
27 | private static String getHelperString(@StringRes final int prefKey, final int defValue) {
28 | return sharedPrefs.getString(getPrefKey(prefKey), getPrefKey(defValue));
29 | }
30 |
31 | /**
32 | * Compares the preference's current value to the called prefKey.
33 | *
34 | * @param currentKeyValue the current key string value of a prefKey
35 | * @param prefKey a passed prefKey
36 | * @return true if the prefKey's current value is equal to the passed prefKey, false otherwise
37 | */
38 | private static boolean getEquals(final String currentKeyValue, @StringRes final int prefKey) {
39 | return currentKeyValue.equals(getPrefKey(prefKey));
40 | }
41 |
42 | public static boolean getShowAngle() {
43 | return getHelperBoolean(PrefKeys.PREF_SHOW_ANGLE, true);
44 | }
45 |
46 | public static String getDisplayType() {
47 | return getHelperString(PrefKeys.PREF_DISPLAY_TYPE, PrefKeys.PREF_DISPLAY_TYPE_ANGLE);
48 | }
49 |
50 | public static boolean isDisplayTypeInclination() {
51 | return getEquals(getDisplayType(), PrefKeys.PREF_DISPLAY_TYPE_INCLINATION);
52 | }
53 |
54 | public static String getDisplayTypeFormat() {
55 | // format of default display type (angle)
56 | String format = "00.0\u2009°";
57 | if (isDisplayTypeInclination()) {
58 | format = "000.0\u2009'%'";
59 | }
60 | return format;
61 | }
62 |
63 | public static String getDisplayTypeBackgroundText() {
64 | // background text of default display type (angle)
65 | String backgroundText = "88.8\u2009°";
66 | if (isDisplayTypeInclination()) {
67 | backgroundText = "888.8\u2009%";
68 | }
69 | return backgroundText;
70 | }
71 |
72 | public static float getDisplayTypeMax() {
73 | // max of default display type (angle)
74 | float max = 99.9f;
75 | if (isDisplayTypeInclination()) {
76 | max = 999.9f;
77 | }
78 | return max;
79 | }
80 |
81 | public static boolean getOrientationLocked() {
82 | return getHelperBoolean(PrefKeys.PREF_LOCK_ORIENTATION, false);
83 | }
84 |
85 | private static String getViscosity() {
86 | return getHelperString(PrefKeys.PREF_VISCOSITY, PrefKeys.PREF_VISCOSITY_MEDIUM);
87 | }
88 |
89 | public static boolean isViscosityLow() {
90 | return getEquals(getViscosity(), PrefKeys.PREF_VISCOSITY_LOW);
91 | }
92 |
93 | public static boolean isViscosityHigh() {
94 | return getEquals(getViscosity(), PrefKeys.PREF_VISCOSITY_HIGH);
95 | }
96 |
97 | public static double getViscosityCoefficient() {
98 | // coefficient of default viscosity (medium)
99 | double coeff = 0.4d;
100 | if (isViscosityLow()) {
101 | coeff = 0.6d;
102 | } else if (isViscosityHigh()) {
103 | coeff = 0.2d;
104 | }
105 | return coeff;
106 | }
107 |
108 | public static boolean getSoundEnabled() {
109 | return getHelperBoolean(PrefKeys.PREF_ENABLE_SOUND, false);
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/view/RulerView.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.view;
2 |
3 | // taken from https://github.com/SecUSo/privacy-friendly-ruler, published under GPL3.0 license
4 |
5 | import android.content.Context;
6 | import android.graphics.Canvas;
7 | import android.graphics.Paint;
8 | import android.graphics.Path;
9 | import android.view.View;
10 |
11 | import androidx.core.content.ContextCompat;
12 | import org.woheller69.level.R;
13 |
14 | public class RulerView extends View {
15 |
16 | double dpmm;
17 | double heightPx;
18 | double heightmm;
19 | double heightFracInch;
20 | double widthPx;
21 | double dpfi;
22 | float lineWidth;
23 | int textSize ;
24 | int db;
25 |
26 | public RulerView(Context context, double ydpmm, double ydpi) {
27 | super(context);
28 |
29 | dpmm = ydpmm;
30 | dpfi = ydpi;
31 |
32 | db = ContextCompat.getColor(context, R.color.black);
33 | textSize = (int)(dpmm *2.5);
34 | lineWidth = (float)(dpmm*0.15);
35 | }
36 |
37 | @Override
38 | protected void onDraw(Canvas canvas) {
39 | super.onDraw(canvas);
40 |
41 | heightPx = this.getHeight();
42 | widthPx = this.getWidth();
43 | heightmm = heightPx/dpmm;
44 | heightFracInch = heightPx/dpfi;
45 |
46 | Paint paint = new Paint();
47 | paint.setAntiAlias(true);
48 | paint.setColor(db);
49 | paint.setAlpha(255);
50 | paint.setTextSize(textSize);
51 | paint.setStrokeWidth(lineWidth);
52 |
53 | drawLeftCm(canvas, paint);
54 | drawRightIn(canvas, paint);
55 |
56 | }
57 |
58 | private void drawLeftCm(Canvas canvas, Paint paint){
59 | for (int i = 0; i < heightmm; i++){
60 | if (i%10 == 0) {
61 | //draw 8mm line every cm
62 | canvas.drawLine(0, (float)dpmm*i, (float)dpmm*8, (float)dpmm*i, paint);
63 | //draw a number every cm
64 | canvas.drawText(""+i/10, (float)dpmm*8+(textSize/5f), (float)(dpmm*i+textSize), paint);
65 | } else if (i%5 == 0) {
66 | //draw 5mm line every 5mm
67 | canvas.drawLine(0, (float)dpmm*i, (float)dpmm*5, (float)dpmm*i, paint);
68 | } else {
69 | //draw 3mm line every mm
70 | canvas.drawLine(0, (float)dpmm*i, (float)dpmm*3, (float)dpmm*i, paint);
71 | }
72 | }
73 | }
74 |
75 | private void drawRightIn(Canvas canvas, Paint paint){
76 | Path path = new Path();
77 |
78 | for (int i = 0; i < (heightFracInch); i++){
79 | if (i%32 == 0) {
80 | //draw 8mm line every inch
81 | canvas.drawLine((float)(widthPx-dpmm*(8)), (float)(heightPx- dpfi *(i)),
82 | (float)(widthPx), (float)(heightPx-dpfi*(i)), paint);
83 | //draw a number every inch
84 | path.reset();
85 | path.moveTo((float)(widthPx-dpmm*(8)-textSize/5), (float)(heightPx- dpfi *(i)-textSize*0.25));
86 | path.lineTo((float)(widthPx-dpmm*(8)-textSize/5), (float)(heightPx- dpfi *(i)-textSize));
87 | canvas.drawTextOnPath(""+i/32, path, 0, 0, paint);
88 | } else if (i%16 == 0) {
89 | //draw 6mm line every 1/2 inch
90 | canvas.drawLine((float)(widthPx-dpmm*(6)), (float)(heightPx- dpfi *(i)),
91 | (float)(widthPx), (float)(heightPx- dpfi *(i)), paint);
92 | } else if (i%8 == 0) {
93 | //draw 4mm line every 1/4 inch
94 | canvas.drawLine((float)(widthPx-dpmm*(4)), (float)(heightPx- dpfi *(i)),
95 | (float)(widthPx), (float)(heightPx- dpfi *(i)), paint);
96 | } else if (i%4 == 0) {
97 | //draw 3mm line every 1/8 inch
98 | canvas.drawLine((float)(widthPx-dpmm*(3)), (float)(heightPx- dpfi *(i)),
99 | (float)(widthPx), (float)(heightPx- dpfi *(i)), paint);
100 | } else if (i%2 == 0) {
101 | //draw 2mm line every 1/16 inch
102 | canvas.drawLine((float)(widthPx-dpmm*(2)), (float)(heightPx- dpfi *(i)),
103 | (float)(widthPx), (float)(heightPx- dpfi *(i)), paint);
104 | } else {
105 | //draw 1.5mm line every 1/32 inch
106 | canvas.drawLine((float)(widthPx-dpmm*(1.5)), (float)(heightPx- dpfi *(i)),
107 | (float)(widthPx), (float)(heightPx- dpfi *(i)), paint);
108 | }
109 | }
110 | }
111 |
112 | public void setCalib(double ydpmm, double ydpi) {
113 | dpmm=ydpmm;
114 | dpfi=ydpi;
115 | invalidate();
116 | requestLayout();
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/ic_bubble.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_fine.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
33 |
34 |
--------------------------------------------------------------------------------
/ic_coarse.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ```
2 | Google has announced that, starting in 2026/2027, all apps on certified Android devices
3 | will require the developer to submit personal identity details directly to Google.
4 | Since the developers of this app do not agree to this requirement, this app will no longer
5 | work on certified Android devices after that time.
6 | ```
7 |
8 | Send a coffee to
9 | woheller69@t-online.de
10 |
11 |
12 |
13 | Or via this link (with fees)
14 | 
15 |
16 |
17 | | **RadarWeather** | **Gas Prices** | **Smart Eggtimer** |
18 | |:---:|:---:|:---:|
19 | | [
](https://f-droid.org/packages/org.woheller69.weather/) | [
](https://f-droid.org/packages/org.woheller69.spritpreise/) | [
](https://f-droid.org/packages/org.woheller69.eggtimer/) |
20 | | **Bubble** | **hEARtest** | **GPS Cockpit** |
21 | | [
](https://f-droid.org/packages/org.woheller69.level/) | [
](https://f-droid.org/packages/org.woheller69.audiometry/) | [
](https://f-droid.org/packages/org.woheller69.gpscockpit/) |
22 | | **Audio Analyzer** | **LavSeeker** | **TimeLapseCam** |
23 | | [
](https://f-droid.org/packages/org.woheller69.audio_analyzer_for_android/) |[
](https://f-droid.org/packages/org.woheller69.lavatories/) | [
](https://f-droid.org/packages/org.woheller69.TimeLapseCam/) |
24 | | **Arity** | **Cirrus** | **solXpect** |
25 | | [
](https://f-droid.org/packages/org.woheller69.arity/) | [
](https://f-droid.org/packages/org.woheller69.omweather/) | [
](https://f-droid.org/packages/org.woheller69.solxpect/) |
26 | | **gptAssist** | **dumpSeeker** | **huggingAssist** |
27 | | [
](https://f-droid.org/packages/org.woheller69.gptassist/) | [
](https://f-droid.org/packages/org.woheller69.dumpseeker/) | [
](https://f-droid.org/packages/org.woheller69.hugassist/) |
28 | | **FREE Browser** | **whoBIRD** | **PeakOrama** |
29 | | [
](https://f-droid.org/packages/org.woheller69.browser/) | [
](https://f-droid.org/packages/org.woheller69.whobird/) | [
](https://f-droid.org/packages/org.woheller69.PeakOrama/) |
30 | | **Whisper** | **Seamless** | |
31 | | [
](https://f-droid.org/packages/org.woheller69.whisper/) | [
](https://f-droid.org/packages/org.woheller69.seemless/) | |
32 |
33 | # Bubble: Spirit level and ruler
34 |
35 |
36 |
37 | With Bubble you can measure angles and inclination.
38 |
39 | Simply align one of your phone's four sides with an object or place it on a level surface to determine its orientation.
40 |
41 | A ruler in cm and inches is also available.
42 |
43 | Experience a user-friendly and ad-free solution with no permissions required.
44 |
45 | [
](https://f-droid.org/packages/org.woheller69.level/)
48 |
49 | This is an updated fork of https://f-droid.org/packages/net.androgames.level/ which has not been revised since 2014.
50 |
51 | ## License
52 |
53 | RulerView taken from https://github.com/SecUSo/privacy-friendly-ruler, published under GPL3.0 license
54 |
55 | ```
56 | An Android Bubble Level application.
57 |
58 | Copyright (C) 2014 Antoine Vianey
59 | Copyright (C) 2021- woheller69
60 |
61 | This program is free software: you can redistribute it and/or modify
62 | it under the terms of the GNU General Public License as published by
63 | the Free Software Foundation, either version 3 of the License, or
64 | (at your option) any later version.
65 |
66 | Level is distributed in the hope that it will be useful,
67 | but WITHOUT ANY WARRANTY; without even the implied warranty of
68 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
69 | GNU General Public License for more details.
70 |
71 | You should have received a copy of the GNU General Public License
72 | along with Level. If not, see
73 | ```
74 |
--------------------------------------------------------------------------------
/ic_launcher_monochrome.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/ic_launcher_foreground.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/ic_fine.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/orientation/OrientationProvider.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level.orientation;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import android.content.SharedPreferences.Editor;
6 | import android.hardware.Sensor;
7 | import android.hardware.SensorEvent;
8 | import android.hardware.SensorEventListener;
9 | import android.hardware.SensorManager;
10 | import android.view.Surface;
11 |
12 | import androidx.appcompat.app.AppCompatActivity;
13 |
14 | import java.util.Arrays;
15 | import java.util.Collections;
16 | import java.util.List;
17 |
18 | /*
19 | * This file is part of Level (an Android Bubble Level).
20 | *
21 | *
22 | * Copyright (C) 2014 Antoine Vianey
23 | *
24 | * Level is free software: you can redistribute it and/or modify
25 | * it under the terms of the GNU General Public License as published by
26 | * the Free Software Foundation, either version 3 of the License, or
27 | * (at your option) any later version.
28 | *
29 | * Level is distributed in the hope that it will be useful,
30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 | * GNU General Public License for more details.
33 | *
34 | * You should have received a copy of the GNU General Public License
35 | * along with Level. If not, see
36 | */
37 | public class OrientationProvider implements SensorEventListener {
38 |
39 | private static final int MIN_VALUES = 20;
40 |
41 | /**
42 | * Calibration
43 | */
44 | private static final String SAVED_PITCH = "pitch.";
45 | private static final String SAVED_ROLL = "roll.";
46 | private static final String SAVED_BALANCE = "balance.";
47 | private static OrientationProvider provider;
48 | /**
49 | * Calibration
50 | */
51 | private final float[] calibratedPitch = new float[5];
52 | private final float[] calibratedRoll = new float[5];
53 | private final float[] calibratedBalance = new float[5];
54 | /**
55 | * Rotation Matrix
56 | */
57 | private final float[] MAG = new float[]{1f, 1f, 1f};
58 | private final float[] I = new float[16];
59 | private final float[] R = new float[16];
60 | private final float[] outR = new float[16];
61 | private final float[] LOC = new float[3];
62 | /**
63 | * Orientation
64 | */
65 | private float pitch;
66 | private float roll;
67 | private final int displayOrientation;
68 | private Sensor sensor;
69 | private SensorManager sensorManager;
70 | private OrientationListener listener;
71 | /**
72 | * indicates whether or not Accelerometer Sensor is supported
73 | */
74 | private Boolean supported;
75 | /**
76 | * indicates whether or not Accelerometer Sensor is running
77 | */
78 | private boolean running = false;
79 | private boolean calibrating = false;
80 | private float balance;
81 | private float tmp;
82 | private float oldPitch;
83 | private float oldRoll;
84 | private float oldBalance;
85 | private float minStep = 360;
86 | private float refValues = 0;
87 | private Orientation orientation;
88 | private boolean locked;
89 | private final AppCompatActivity activity;
90 |
91 | public OrientationProvider(Context context) {
92 | activity = (AppCompatActivity) context;
93 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
94 | this.displayOrientation = activity.getDisplay().getRotation();
95 | } else {
96 | this.displayOrientation = activity.getWindowManager().getDefaultDisplay().getRotation();
97 | }
98 | }
99 |
100 | public static OrientationProvider getInstance(Context context) {
101 | if (provider == null) {
102 | provider = new OrientationProvider(context);
103 | }
104 | return provider;
105 | }
106 |
107 | /**
108 | * Returns true if the manager is listening to orientation changes
109 | */
110 | public boolean isListening() {
111 | return running;
112 | }
113 |
114 | /**
115 | * Unregisters listeners
116 | */
117 | public void stopListening() {
118 | running = false;
119 | try {
120 | if (sensorManager != null) {
121 | sensorManager.unregisterListener(this);
122 | }
123 | } catch (Exception e) {
124 | }
125 | }
126 |
127 | private List getRequiredSensors() {
128 | return Collections.singletonList(
129 | Sensor.TYPE_ACCELEROMETER
130 | );
131 | }
132 |
133 | /**
134 | * Returns true if at least one Accelerometer sensor is available
135 | */
136 | public boolean isSupported() {
137 | if (supported == null) {
138 | if (activity != null) {
139 | sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
140 | boolean supported = true;
141 | for (int sensorType : getRequiredSensors()) {
142 | List sensors = sensorManager.getSensorList(sensorType);
143 | supported = (sensors.size() > 0) && supported;
144 | }
145 | this.supported = supported;
146 | return supported;
147 | }
148 | }
149 | return supported;
150 | }
151 |
152 |
153 | /**
154 | * Registers a listener and start listening
155 | * callback for accelerometer events
156 | */
157 | public void startListening(OrientationListener orientationListener) {
158 | // load calibration
159 | calibrating = false;
160 | Arrays.fill(calibratedPitch, 0);
161 | Arrays.fill(calibratedRoll, 0);
162 | Arrays.fill(calibratedBalance, 0);
163 | SharedPreferences prefs = activity.getPreferences(Context.MODE_PRIVATE);
164 | for (Orientation orientation : Orientation.values()) {
165 | calibratedPitch[orientation.ordinal()] =
166 | prefs.getFloat(SAVED_PITCH + orientation.toString(), 0);
167 | calibratedRoll[orientation.ordinal()] =
168 | prefs.getFloat(SAVED_ROLL + orientation.toString(), 0);
169 | calibratedBalance[orientation.ordinal()] =
170 | prefs.getFloat(SAVED_BALANCE + orientation.toString(), 0);
171 | }
172 | // register listener and start listening
173 | sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE);
174 | running = true;
175 | for (int sensorType : getRequiredSensors()) {
176 | List sensors = sensorManager.getSensorList(sensorType);
177 | if (sensors.size() > 0) {
178 | sensor = sensors.get(0);
179 | running = sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL) && running;
180 | }
181 | }
182 | if (running) {
183 | listener = orientationListener;
184 | }
185 | }
186 |
187 | public void onAccuracyChanged(Sensor sensor, int accuracy) {
188 | }
189 |
190 | public void onSensorChanged(SensorEvent event) {
191 |
192 | oldPitch = pitch;
193 | oldRoll = roll;
194 | oldBalance = balance;
195 |
196 | SensorManager.getRotationMatrix(R, I, event.values, MAG);
197 |
198 | // compute pitch, roll & balance
199 | switch (displayOrientation) {
200 | case Surface.ROTATION_270:
201 | SensorManager.remapCoordinateSystem(
202 | R,
203 | SensorManager.AXIS_MINUS_Y,
204 | SensorManager.AXIS_X,
205 | outR);
206 | break;
207 | case Surface.ROTATION_180:
208 | SensorManager.remapCoordinateSystem(
209 | R,
210 | SensorManager.AXIS_MINUS_X,
211 | SensorManager.AXIS_MINUS_Y,
212 | outR);
213 | break;
214 | case Surface.ROTATION_90:
215 | SensorManager.remapCoordinateSystem(
216 | R,
217 | SensorManager.AXIS_Y,
218 | SensorManager.AXIS_MINUS_X,
219 | outR);
220 | break;
221 | case Surface.ROTATION_0:
222 | default:
223 | SensorManager.remapCoordinateSystem(
224 | R,
225 | SensorManager.AXIS_X,
226 | SensorManager.AXIS_Y,
227 | outR);
228 | break;
229 | }
230 |
231 | SensorManager.getOrientation(outR, LOC);
232 |
233 | // normalize z on ux, uy
234 | tmp = (float) Math.sqrt(outR[8] * outR[8] + outR[9] * outR[9]);
235 | tmp = (tmp == 0 ? 0 : outR[8] / tmp);
236 |
237 | // LOC[0] compass
238 | pitch = (float) Math.toDegrees(LOC[1]);
239 | roll = -(float) Math.toDegrees(LOC[2]);
240 | balance = (float) Math.toDegrees(Math.asin(tmp));
241 |
242 | // calculating minimal sensor step
243 | if (oldRoll != roll || oldPitch != pitch || oldBalance != balance) {
244 | if (oldPitch != pitch) {
245 | minStep = Math.min(minStep, Math.abs(pitch - oldPitch));
246 | }
247 | if (oldRoll != roll) {
248 | minStep = Math.min(minStep, Math.abs(roll - oldRoll));
249 | }
250 | if (oldBalance != balance) {
251 | minStep = Math.min(minStep, Math.abs(balance - oldBalance));
252 | }
253 | if (refValues < MIN_VALUES) {
254 | refValues++;
255 | }
256 | }
257 |
258 | if (!locked || orientation == null) {
259 | if (pitch < -45 && pitch > -135) {
260 | // top side up
261 | orientation = Orientation.TOP;
262 | } else if (pitch > 45 && pitch < 135) {
263 | // bottom side up
264 | orientation = Orientation.BOTTOM;
265 | } else if (roll > 45) {
266 | // right side up
267 | orientation = Orientation.RIGHT;
268 | } else if (roll < -45) {
269 | // left side up
270 | orientation = Orientation.LEFT;
271 | } else {
272 | // landing
273 | orientation = Orientation.LANDING;
274 | }
275 | }
276 |
277 | if (calibrating) {
278 | calibrating = false;
279 | Editor editor = activity.getPreferences(Context.MODE_PRIVATE).edit();
280 | editor.putFloat(SAVED_PITCH + orientation.toString(), pitch);
281 | editor.putFloat(SAVED_ROLL + orientation.toString(), roll);
282 | editor.putFloat(SAVED_BALANCE + orientation.toString(), balance);
283 | final boolean success = editor.commit();
284 | if (success) {
285 | calibratedPitch[orientation.ordinal()] = pitch;
286 | calibratedRoll[orientation.ordinal()] = roll;
287 | calibratedBalance[orientation.ordinal()] = balance;
288 | }
289 | listener.onCalibrationSaved(success);
290 | pitch = 0;
291 | roll = 0;
292 | balance = 0;
293 | } else {
294 | pitch -= calibratedPitch[orientation.ordinal()];
295 | roll -= calibratedRoll[orientation.ordinal()];
296 | balance -= calibratedBalance[orientation.ordinal()];
297 | }
298 |
299 | // propagation of the orientation
300 | listener.onOrientationChanged(orientation, pitch, roll, balance);
301 | }
302 |
303 | /**
304 | * Tell the provider to restore the calibration
305 | * to the default factory values
306 | */
307 | public final void resetCalibration() {
308 | boolean success = false;
309 | try {
310 | success = activity.getPreferences(
311 | Context.MODE_PRIVATE).edit().clear().commit();
312 | } catch (Exception e) {
313 | }
314 | if (success) {
315 | Arrays.fill(calibratedPitch, 0);
316 | Arrays.fill(calibratedRoll, 0);
317 | Arrays.fill(calibratedBalance, 0);
318 | }
319 | if (listener != null) {
320 | listener.onCalibrationReset(success);
321 | }
322 | }
323 |
324 |
325 | /**
326 | * Tell the provider to save the calibration
327 | * The calibration is actually saved on the next
328 | * sensor change event
329 | */
330 | public final void saveCalibration() {
331 | calibrating = true;
332 | }
333 |
334 | public void setLocked(boolean locked) {
335 | this.locked = locked;
336 | }
337 |
338 | /**
339 | * Return the minimal sensor step
340 | *
341 | * @return the minimal sensor step
342 | * 0 if not yet known
343 | */
344 | public float getSensibility() {
345 | if (refValues >= MIN_VALUES) {
346 | return minStep;
347 | } else {
348 | return 0;
349 | }
350 | }
351 | }
352 |
--------------------------------------------------------------------------------
/app/src/main/java/org/woheller69/level/Level.java:
--------------------------------------------------------------------------------
1 | package org.woheller69.level;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.content.SharedPreferences;
7 | import android.content.res.Configuration;
8 | import android.content.res.TypedArray;
9 | import android.graphics.PorterDuff;
10 | import android.media.AudioAttributes;
11 | import android.media.AudioManager;
12 | import android.media.SoundPool;
13 | import android.net.Uri;
14 | import android.os.Build;
15 | import android.os.Bundle;
16 | import android.util.TypedValue;
17 | import android.view.Menu;
18 | import android.view.MenuItem;
19 | import android.view.View;
20 | import android.view.ViewGroup;
21 | import android.view.WindowInsetsController;
22 | import android.view.WindowManager;
23 | import android.widget.RelativeLayout;
24 | import android.widget.SeekBar;
25 | import android.widget.Toast;
26 |
27 | import androidx.appcompat.app.AlertDialog;
28 | import androidx.appcompat.app.AppCompatActivity;
29 | import androidx.appcompat.view.menu.MenuBuilder;
30 | import androidx.appcompat.widget.AppCompatImageButton;
31 | import androidx.core.content.ContextCompat;
32 | import androidx.preference.PreferenceManager;
33 |
34 | import org.woheller69.freeDroidWarn.FreeDroidWarn;
35 | import org.woheller69.level.orientation.Orientation;
36 | import org.woheller69.level.orientation.OrientationListener;
37 | import org.woheller69.level.orientation.OrientationProvider;
38 | import org.woheller69.level.util.PreferenceHelper;
39 | import org.woheller69.level.view.LevelView;
40 | import org.woheller69.level.view.RulerView;
41 | import org.woheller69.level.view.VerticalSeekBar;
42 |
43 | /*
44 | * This file is part of Level (an Android Bubble Level).
45 | *
46 | *
47 | * Copyright (C) 2014 Antoine Vianey
48 | *
49 | * Level is free software: you can redistribute it and/or modify
50 | * it under the terms of the GNU General Public License as published by
51 | * the Free Software Foundation, either version 3 of the License, or
52 | * (at your option) any later version.
53 | *
54 | * Level is distributed in the hope that it will be useful,
55 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
56 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
57 | * GNU General Public License for more details.
58 | *
59 | * You should have received a copy of the GNU General Public License
60 | * along with Level. If not, see
61 | */
62 | public class Level extends AppCompatActivity implements OrientationListener {
63 |
64 | private static OrientationProvider provider;
65 |
66 | private LevelView levelView;
67 | private RulerView rulerView;
68 | private VerticalSeekBar rulerCalView;
69 | private VerticalSeekBar rulerCoarseCalView;
70 | private AppCompatImageButton rulerResetButtonView;
71 |
72 | /**
73 | * Gestion du son
74 | */
75 | private SoundPool soundPool;
76 | private boolean soundEnabled;
77 | private int bipSoundID;
78 | private int bipRate;
79 | private long lastBip;
80 | private Context context;
81 |
82 | public static OrientationProvider getProvider() {
83 | return provider;
84 | }
85 |
86 | @Override
87 | protected void onCreate(Bundle savedInstanceState) {
88 | super.onCreate(savedInstanceState);
89 | context = this;
90 | setContentView(R.layout.main);
91 | if (getSupportActionBar() != null) {
92 | getSupportActionBar().setDisplayShowHomeEnabled(true);
93 | }
94 |
95 | if (Build.VERSION.SDK_INT > Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
96 | int nightModeFlags = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
97 | boolean isDarkMode = (nightModeFlags == Configuration.UI_MODE_NIGHT_YES);
98 | WindowInsetsController insetsController = getWindow().getInsetsController();
99 | if (insetsController != null) {
100 | if (isDarkMode) {
101 | // Dark mode: remove light status bar appearance (use light icons)
102 | insetsController.setSystemBarsAppearance(
103 | 0,
104 | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
105 | );
106 | } else {
107 | // Light mode: enable light status bar appearance (dark icons)
108 | insetsController.setSystemBarsAppearance(
109 | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
110 | WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
111 | );
112 | }
113 | }
114 | }
115 |
116 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
117 | levelView = findViewById(R.id.main_levelView);
118 | // sound
119 |
120 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
121 | soundPool = new SoundPool.Builder()
122 | .setMaxStreams(1)
123 | .setAudioAttributes(
124 | new AudioAttributes.Builder()
125 | .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
126 | .build())
127 | .build();
128 | } else {
129 | soundPool = new SoundPool(1, AudioManager.STREAM_RING, 0);
130 | }
131 |
132 | bipSoundID = soundPool.load(this, R.raw.bip, 1);
133 | bipRate = getResources().getInteger(R.integer.bip_rate);
134 | FreeDroidWarn.showWarningOnUpgrade(this, BuildConfig.VERSION_CODE);
135 | }
136 |
137 | @SuppressLint("RestrictedApi")
138 | @Override
139 | public boolean onCreateOptionsMenu(Menu menu) {
140 | getMenuInflater().inflate(R.menu.main, menu);
141 | menu.findItem(R.id.menu_ruler).setChecked(rulerView!=null);
142 | menu.findItem(R.id.menu_ruler).setIcon(rulerView==null ? R.drawable.ic_ruler : R.drawable.ic_bubble);
143 | menu.findItem(R.id.menu_settings).setVisible(rulerView==null);
144 | if (menu instanceof MenuBuilder) {
145 | ((MenuBuilder) menu).setOptionalIconsVisible(true);
146 | }
147 | return true;
148 | }
149 |
150 | /* Handles item selections */
151 | public boolean onOptionsItemSelected(MenuItem item) {
152 | if (item.getItemId() == R.id.menu_calibrate) {
153 | if (rulerView==null){
154 | new AlertDialog.Builder(this)
155 | .setTitle(R.string.calibrate_title)
156 | .setIcon(null)
157 | .setCancelable(true)
158 | .setPositiveButton(R.string.calibrate, (dialog, id) -> provider.saveCalibration())
159 | .setNegativeButton(android.R.string.cancel, null)
160 | .setNeutralButton(R.string.reset, (dialog, id) -> provider.resetCalibration())
161 | .setMessage(R.string.calibrate_message)
162 | .show();
163 | } else {
164 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
165 | int progress = sp.getInt("pref_rulercal",100);
166 | int coarseprogress = sp.getInt("pref_rulercoarsecal",2000);
167 | RelativeLayout rulerLayout = (RelativeLayout) findViewById(R.id.main_layout);
168 | if (rulerCalView == null){
169 | Toast.makeText(this,getString(R.string.calibrate)+" \u25b2\u25bc", Toast.LENGTH_LONG).show();
170 | rulerCalView = new VerticalSeekBar(this);
171 | rulerCalView.setMax(200);
172 | rulerCalView.setProgress(progress);
173 | rulerCalView.setThumb(ContextCompat.getDrawable(context, R.drawable.ic_fine));
174 | rulerCalView.getThumb().setColorFilter(getThemeColor(context,R.attr.colorAccent), PorterDuff.Mode.MULTIPLY);
175 | RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
176 | layoutParams.setMargins(rulerLayout.getWidth()*3/8,0,0,0);
177 | rulerCalView.setLayoutParams(layoutParams);
178 | rulerCoarseCalView = new VerticalSeekBar(this);
179 | rulerCoarseCalView.setMax(6000);
180 | rulerCoarseCalView.setProgress(coarseprogress);
181 | rulerCoarseCalView.setThumb(ContextCompat.getDrawable(context, R.drawable.ic_coarse));
182 | rulerCoarseCalView.getThumb().setColorFilter(getThemeColor(context,R.attr.colorAccent), PorterDuff.Mode.MULTIPLY);
183 | RelativeLayout.LayoutParams layoutParams2 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);
184 | layoutParams2.setMargins(0,0,rulerLayout.getWidth()*3/8,0);
185 | layoutParams2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
186 | rulerCoarseCalView.setLayoutParams(layoutParams2);
187 |
188 | rulerResetButtonView = new AppCompatImageButton(this);
189 | RelativeLayout.LayoutParams layoutParams3 = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
190 | layoutParams3.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
191 | layoutParams3.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE);
192 | rulerResetButtonView.setLayoutParams(layoutParams3);
193 | rulerResetButtonView.setImageResource(R.drawable.ic_reset);
194 | rulerLayout.addView(rulerResetButtonView);
195 | rulerLayout.addView(rulerCalView);
196 | rulerLayout.addView(rulerCoarseCalView);
197 |
198 | rulerCalView.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
199 | @Override
200 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
201 | rulerView.setCalib(getDpmmCal(progress,rulerCoarseCalView.getProgress()), getDpmmCal(progress,rulerCoarseCalView.getProgress())*25.4/32);
202 | SharedPreferences.Editor editor = sp.edit();
203 | editor.putInt("pref_rulercal",progress);
204 | editor.apply();
205 | }
206 | @Override
207 | public void onStartTrackingTouch(SeekBar seekBar) {}
208 | @Override
209 | public void onStopTrackingTouch(SeekBar seekBar) {}
210 | });
211 | rulerCoarseCalView.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
212 | @Override
213 | public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
214 | rulerView.setCalib(getDpmmCal(rulerCalView.getProgress(),progress), getDpmmCal(rulerCalView.getProgress(),progress)*25.4/32);
215 | SharedPreferences.Editor editor = sp.edit();
216 | editor.putInt("pref_rulercoarsecal",progress);
217 | editor.apply();
218 | }
219 | @Override
220 | public void onStartTrackingTouch(SeekBar seekBar) {}
221 | @Override
222 | public void onStopTrackingTouch(SeekBar seekBar) {}
223 | });
224 | rulerResetButtonView.setOnClickListener(view -> {
225 | rulerCalView.setProgress(100);
226 | rulerCoarseCalView.setProgress(2000);
227 | });
228 | } else {
229 | rulerLayout.removeView(rulerCalView);
230 | rulerLayout.removeView(rulerCoarseCalView);
231 | rulerLayout.removeView(rulerResetButtonView);
232 | rulerCalView = null;
233 | rulerCoarseCalView = null;
234 | rulerResetButtonView = null;
235 | }
236 | }
237 |
238 | return true;
239 | } else if (item.getItemId() == R.id.menu_settings) {
240 | startActivity(new Intent(this, SettingsActivity.class));
241 | return true;
242 | } else if (item.getItemId() == R.id.menu_about) {
243 | startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/woheller69/level")));
244 | recreate(); //fix strange action bar position when coming from ruler
245 | return true;
246 | } else if (item.getItemId() == R.id.menu_ruler) {
247 | showRuler(!item.isChecked());
248 | }
249 | return false;
250 | }
251 |
252 | private void showRuler(boolean ruler) {
253 | if (ruler){
254 | SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
255 | RelativeLayout rulerLayout = (RelativeLayout) findViewById(R.id.main_layout);
256 | int progress = sp.getInt("pref_rulercal",100);
257 | int coarseProgress = sp.getInt("pref_rulercoarsecal",2000);
258 | float dpmm = getDpmmCal(progress,coarseProgress);
259 |
260 | rulerView = new RulerView(this, dpmm, dpmm*25.4/32);
261 | rulerView.setBackgroundColor(ContextCompat.getColor(this,R.color.silver));
262 | rulerLayout.addView(rulerView);
263 | levelView.setVisibility(View.INVISIBLE);
264 | invalidateOptionsMenu();
265 | } else {
266 | levelView.setVisibility(View.VISIBLE);
267 | RelativeLayout rulerLayout = (RelativeLayout) findViewById(R.id.main_layout);
268 | if (rulerView!=null) rulerLayout.removeView(rulerView);
269 | rulerView = null;
270 | if (rulerCalView !=null) rulerLayout.removeView(rulerCalView);
271 | rulerCalView = null;
272 | if (rulerCoarseCalView !=null) rulerLayout.removeView(rulerCoarseCalView);
273 | rulerCoarseCalView = null;
274 | if (rulerResetButtonView !=null) rulerLayout.removeView(rulerResetButtonView);
275 | rulerResetButtonView = null;
276 | getWindow().getDecorView().setSystemUiVisibility(0);
277 | invalidateOptionsMenu();
278 | }
279 |
280 | }
281 |
282 | @Override
283 | protected void onResume() {
284 | super.onResume();
285 | provider = OrientationProvider.getInstance(this);
286 | // chargement des effets sonores
287 | soundEnabled = PreferenceHelper.getSoundEnabled();
288 | // orientation manager
289 | if (provider.isSupported()) {
290 | provider.startListening(this);
291 | } else {
292 | Toast.makeText(this, getText(R.string.not_supported), Toast.LENGTH_LONG).show();
293 | }
294 | }
295 |
296 | @Override
297 | protected void onPause() {
298 | super.onPause();
299 | showRuler(false);
300 | if (provider.isListening()) {
301 | provider.stopListening();
302 | }
303 | }
304 |
305 | @Override
306 | public void onDestroy() {
307 | if (soundPool != null) {
308 | soundPool.release();
309 | }
310 | super.onDestroy();
311 | }
312 |
313 | @Override
314 | public void onOrientationChanged(Orientation orientation, float pitch, float roll, float balance) {
315 | if (soundEnabled
316 | && orientation.isLevel(pitch, roll, balance, provider.getSensibility())
317 | && System.currentTimeMillis() - lastBip > bipRate) {
318 | AudioManager mgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
319 | float streamVolumeCurrent = mgr.getStreamVolume(AudioManager.STREAM_RING);
320 | float streamVolumeMax = mgr.getStreamMaxVolume(AudioManager.STREAM_RING);
321 | float volume = streamVolumeCurrent / streamVolumeMax;
322 | lastBip = System.currentTimeMillis();
323 | soundPool.play(bipSoundID, volume, volume, 1, 0, 1);
324 | }
325 | levelView.onOrientationChanged(orientation, pitch, roll, balance);
326 | }
327 |
328 | @Override
329 | public void onCalibrationReset(boolean success) {
330 | Toast.makeText(this, success ?
331 | R.string.calibrate_restored : R.string.calibrate_failed,
332 | Toast.LENGTH_LONG).show();
333 | }
334 |
335 | @Override
336 | public void onCalibrationSaved(boolean success) {
337 | Toast.makeText(this, success ?
338 | R.string.calibrate_saved : R.string.calibrate_failed,
339 | Toast.LENGTH_LONG).show();
340 | }
341 |
342 | public float getDpmmCal(int progress, int coarseProgress){
343 | float dpmm = (float) (getResources().getDisplayMetrics().ydpi/25.4);
344 | return dpmm*(1+(progress+coarseProgress-100f-2000f)/5000f);
345 | }
346 |
347 | public static int getThemeColor(Context context, int colorResId) {
348 | TypedValue typedValue = new TypedValue();
349 | TypedArray typedArray = context.obtainStyledAttributes(typedValue.data, new int[] {colorResId});
350 | int color = typedArray.getColor(0, 0);
351 | typedArray.recycle();
352 | return color;
353 | }
354 |
355 | }
356 |
--------------------------------------------------------------------------------