mirror of
https://gitlab.com/oeffi/oeffi.git
synced 2025-07-07 06:08:51 +00:00
Compare commits
199 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f1198671b1 | ||
![]() |
2736bc82dd | ||
![]() |
cd6628088a | ||
![]() |
e7e8af6a10 | ||
![]() |
53c5ea26b6 | ||
![]() |
37949d2628 | ||
![]() |
90c3e70665 | ||
![]() |
d1c124478d | ||
![]() |
004f32b234 | ||
![]() |
e361a6fc06 | ||
![]() |
d76e357603 | ||
![]() |
2f158a9b5b | ||
![]() |
3dfa049ae2 | ||
![]() |
e17a2ff2dc | ||
![]() |
d8b885fca3 | ||
![]() |
71f315ac59 | ||
![]() |
ce7fedc76e | ||
![]() |
3b80a7a3b4 | ||
![]() |
0bd83c0125 | ||
![]() |
c5ee0db526 | ||
![]() |
99b737f237 | ||
![]() |
59168f51c4 | ||
![]() |
eb23268ebc | ||
![]() |
2a1cc53180 | ||
![]() |
b5dac623dd | ||
![]() |
2e00027604 | ||
![]() |
335fdea1f8 | ||
![]() |
75913e122a | ||
![]() |
4357b7a0df | ||
![]() |
40b468d354 | ||
![]() |
efa91b4c67 | ||
![]() |
562d118e79 | ||
![]() |
d4060f7589 | ||
![]() |
078b07340d | ||
![]() |
9197bdbe1a | ||
![]() |
558e1a6cc4 | ||
![]() |
e66388c60d | ||
![]() |
100fb5ab3a | ||
![]() |
abb468772d | ||
![]() |
5eda98e436 | ||
![]() |
05d3623c34 | ||
![]() |
4a17ef441f | ||
![]() |
b1e17c5795 | ||
![]() |
df63f54ab1 | ||
![]() |
b0ea770ba3 | ||
![]() |
d92615efd9 | ||
![]() |
0873bfa3de | ||
![]() |
23a1daf92b | ||
![]() |
30d2e47fc9 | ||
![]() |
c6dcce6049 | ||
![]() |
2c3249838a | ||
![]() |
f7f93c1a88 | ||
![]() |
47734279de | ||
![]() |
1a7e46a3af | ||
![]() |
afdd237cca | ||
![]() |
17727a1e3a | ||
![]() |
70c1ac5fa4 | ||
![]() |
71e68765cd | ||
![]() |
33284c92c2 | ||
![]() |
f4ce1d0e43 | ||
![]() |
8836b3df20 | ||
![]() |
ce6f3a8520 | ||
![]() |
4c8d26dee7 | ||
![]() |
5815a985f5 | ||
![]() |
cf332416b8 | ||
![]() |
bcf34c1de9 | ||
![]() |
4b710e1aad | ||
![]() |
488fbe19fd | ||
![]() |
2843f84b45 | ||
![]() |
332f0c06b8 | ||
![]() |
61c201eb2b | ||
![]() |
bae07f465f | ||
![]() |
ab93873c0e | ||
![]() |
843ed0fa7e | ||
![]() |
ba3a37f6df | ||
![]() |
81a89ec939 | ||
![]() |
2754077ccb | ||
![]() |
80daf5c5c6 | ||
![]() |
1eda102dc0 | ||
![]() |
dc5c69d9ec | ||
![]() |
7c09e85f76 | ||
![]() |
9524f77e10 | ||
![]() |
a4a5774778 | ||
![]() |
54ce45291a | ||
![]() |
b4503f1dec | ||
![]() |
7ac8f6280c | ||
![]() |
45e213b14a | ||
![]() |
5e3204c796 | ||
![]() |
ef47708d0b | ||
![]() |
301b09f16b | ||
![]() |
18415177bd | ||
![]() |
4bdb3598c3 | ||
![]() |
5c6aef0591 | ||
![]() |
843edcb001 | ||
![]() |
42e3ffbc77 | ||
![]() |
ed00894f88 | ||
![]() |
89fa32ef56 | ||
![]() |
a866d66f6c | ||
![]() |
1c353469cd | ||
![]() |
6fb89c878c | ||
![]() |
766d5c0150 | ||
![]() |
1d4fd6e102 | ||
![]() |
1ec70d1886 | ||
![]() |
75e279bb20 | ||
![]() |
56bc7f5278 | ||
![]() |
b919448d01 | ||
![]() |
d4f9ab68f1 | ||
![]() |
8f1c8f1986 | ||
![]() |
d6b9e00937 | ||
![]() |
271659d914 | ||
![]() |
b25e8c14f8 | ||
![]() |
b757b94c55 | ||
![]() |
31a47148d4 | ||
![]() |
1098996918 | ||
![]() |
7de60a14e1 | ||
![]() |
2dc4cc5e16 | ||
![]() |
a9259cfe31 | ||
![]() |
3fb2e68bda | ||
![]() |
696746c894 | ||
![]() |
b10f240ea5 | ||
![]() |
6696c8f293 | ||
![]() |
d926f8b722 | ||
![]() |
e9d10f62b7 | ||
![]() |
337e21ea2b | ||
![]() |
d1c9c5d06c | ||
![]() |
2402abad0d | ||
![]() |
e9aa9419a3 | ||
![]() |
fe6fe32d93 | ||
![]() |
3ab7d48659 | ||
![]() |
12652c3f83 | ||
![]() |
dc36ffe0a0 | ||
![]() |
d2d4cdb58d | ||
![]() |
ff3ae97c01 | ||
![]() |
9830d9b5bc | ||
![]() |
6b3ede94cf | ||
![]() |
1e3ef244b7 | ||
![]() |
d88d18f025 | ||
![]() |
0c894a541d | ||
![]() |
4299a6fd41 | ||
![]() |
d70d84b8b9 | ||
![]() |
1c6dc66814 | ||
![]() |
a5c17eaff2 | ||
![]() |
b7341bf810 | ||
![]() |
6e34a09531 | ||
![]() |
385845c78e | ||
![]() |
75594e2904 | ||
![]() |
5e7614d9f5 | ||
![]() |
16ddf861f3 | ||
![]() |
72c772f334 | ||
![]() |
1e265a61da | ||
![]() |
d67ee8807a | ||
![]() |
b012e7feb1 | ||
![]() |
8f095e9296 | ||
![]() |
324d625d45 | ||
![]() |
1320282a22 | ||
![]() |
4e2280d681 | ||
![]() |
53990a285e | ||
![]() |
ea43d90fb9 | ||
![]() |
1f9ebdf32d | ||
![]() |
02ec2b07cd | ||
![]() |
1b232b3ba5 | ||
![]() |
dd2e65721b | ||
![]() |
52685204ff | ||
![]() |
3cf37274c0 | ||
![]() |
7a609d0452 | ||
![]() |
b4fe055f8a | ||
![]() |
dcceeedd52 | ||
![]() |
8e0d9ef49c | ||
![]() |
2c04846051 | ||
![]() |
7aeee3c505 | ||
![]() |
da08b96180 | ||
![]() |
c8fc8f0ffb | ||
![]() |
25f378d0be | ||
![]() |
ac639a635e | ||
![]() |
2034119b71 | ||
![]() |
7634c116ae | ||
![]() |
619853a04a | ||
![]() |
5fc7486193 | ||
![]() |
5b119a5b3f | ||
![]() |
d296a84934 | ||
![]() |
1a40a3213e | ||
![]() |
34fd491c92 | ||
![]() |
996a89a133 | ||
![]() |
bb4ce986e0 | ||
![]() |
a16e298047 | ||
![]() |
95ea2d72f6 | ||
![]() |
fa4af8051f | ||
![]() |
e2a04c7202 | ||
![]() |
03540a12b7 | ||
![]() |
c021055fdb | ||
![]() |
1cecd76d6d | ||
![]() |
286c375b3a | ||
![]() |
c0248193a3 | ||
![]() |
e34ea78a49 | ||
![]() |
c14a230d94 | ||
![]() |
dedae2266f | ||
![]() |
329e6e5e81 | ||
![]() |
acedc27d52 | ||
![]() |
3cc64ce44e |
89 changed files with 1028 additions and 1988 deletions
5
.dockerignore
Normal file
5
.dockerignore
Normal file
|
@ -0,0 +1,5 @@
|
|||
**/.*
|
||||
**/build.Containerfile
|
||||
**/local.properties
|
||||
**/build
|
||||
**/*.iml
|
|
@ -1,25 +1,33 @@
|
|||
image: ubuntu:focal
|
||||
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
ANDROID_HOME: $PWD/android-sdk
|
||||
ANDROID_SDK_TOOLS: 7583922_latest
|
||||
ANDROID_SDK_LICENSE_HASH: 24333f8a63b6825ea9c5514f83c2829b004d1fee
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
ANDROID_HOME: $PWD/android-sdk
|
||||
|
||||
before_script:
|
||||
- apt-get update
|
||||
- apt-get -y upgrade
|
||||
- apt-get -y install ${JDK_PACKAGE}
|
||||
- apt-get -y install wget gradle
|
||||
- wget --quiet --output-document=commandlinetools-linux.zip https://dl.google.com/android/repository/commandlinetools-linux-${ANDROID_SDK_TOOLS}.zip
|
||||
- mkdir -p ${ANDROID_HOME}
|
||||
- unzip -d ${ANDROID_HOME} commandlinetools-linux.zip
|
||||
- mkdir -p ${ANDROID_HOME}/licenses
|
||||
- echo -e "\n${ANDROID_SDK_LICENSE_HASH}" >> ${ANDROID_HOME}/licenses/android-sdk-license
|
||||
|
||||
build:
|
||||
parallel:
|
||||
matrix:
|
||||
- JDK_PACKAGE: [ openjdk-8-jdk, openjdk-11-jdk ]
|
||||
reference:
|
||||
image: debian:bookworm-slim
|
||||
before_script:
|
||||
- apt-get update
|
||||
- apt-get -y install ca-certificates buildah
|
||||
# switch to iptables legacy, as GitLab CI doesn't support nftables
|
||||
- apt-get -y install --no-install-recommends iptables
|
||||
- update-alternatives --set iptables /usr/sbin/iptables-legacy
|
||||
script:
|
||||
- buildah build --file build.Containerfile --output build .
|
||||
after_script:
|
||||
- sha256sum build/*
|
||||
artifacts:
|
||||
name: oeffi-$CI_JOB_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
|
||||
paths:
|
||||
- build/**
|
||||
|
||||
bookworm-jdk17:
|
||||
image: debian:bookworm-slim
|
||||
script:
|
||||
- apt-get update
|
||||
- apt-get -y install openjdk-17-jdk-headless gradle sdkmanager
|
||||
- yes | sdkmanager --licenses >/dev/null || true
|
||||
- gradle build --stacktrace
|
||||
- gradle --version
|
||||
artifacts:
|
||||
name: oeffi-$CI_JOB_NAME-$CI_COMMIT_REF_SLUG-$CI_COMMIT_SHORT_SHA
|
||||
paths:
|
||||
- oeffi/build/outputs/apk/**/*.apk
|
||||
|
|
57
build.Containerfile
Normal file
57
build.Containerfile
Normal file
|
@ -0,0 +1,57 @@
|
|||
#
|
||||
# Usage:
|
||||
#
|
||||
# docker build --file build.Containerfile --output <outputdir> .
|
||||
# or
|
||||
# podman build --file build.Containerfile --output <outputdir> .
|
||||
#
|
||||
# For improved reproducibility, the project directory entries can be ordered
|
||||
# like this:
|
||||
#
|
||||
# buildah build --cap-add=sys_admin --device /dev/fuse --file build.Containerfile --output <outputdir> .
|
||||
#
|
||||
# In any case, the unsigned APKs are written to the specified output
|
||||
# directory. Use `apksigner` to sign before installing via `adb install`.
|
||||
#
|
||||
|
||||
FROM debian:bookworm-slim AS build-stage
|
||||
|
||||
# install debian packages
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
|
||||
--mount=target=/var/cache/apt,type=cache,sharing=locked \
|
||||
/bin/rm -f /etc/apt/apt.conf.d/docker-clean && \
|
||||
/usr/bin/apt-get update && \
|
||||
/usr/bin/apt-get --yes --no-install-recommends install disorderfs openjdk-17-jdk-headless gradle sdkmanager && \
|
||||
/bin/ln -fs /usr/share/zoneinfo/CET /etc/localtime && \
|
||||
/usr/sbin/dpkg-reconfigure --frontend noninteractive tzdata && \
|
||||
/bin/ln -s /proc/self/mounts /etc/mtab && \
|
||||
/usr/sbin/adduser --disabled-login --gecos "" builder
|
||||
|
||||
# give up privileges
|
||||
USER builder
|
||||
|
||||
# copy project source code
|
||||
WORKDIR /home/builder
|
||||
COPY --chown=builder / project/
|
||||
|
||||
# accept SDK licenses
|
||||
ENV ANDROID_HOME /home/builder/android-sdk
|
||||
RUN --mount=target=/home/builder/android-sdk,type=cache,uid=1000,gid=1000,sharing=locked \
|
||||
yes | /usr/bin/sdkmanager --licenses >/dev/null
|
||||
|
||||
# build project
|
||||
RUN --mount=target=/home/builder/android-sdk,type=cache,uid=1000,gid=1000,sharing=locked \
|
||||
--mount=target=/home/builder/.gradle,type=cache,uid=1000,gid=1000,sharing=locked \
|
||||
if [ -e /dev/fuse ] ; \
|
||||
then /bin/mv project project.u && /bin/mkdir project && \
|
||||
/usr/bin/disorderfs --sort-dirents=yes --reverse-dirents=no project.u project ; \
|
||||
fi && \
|
||||
/usr/bin/gradle --project-dir project/ --no-build-cache --no-daemon --no-parallel clean :oeffi:assembleRelease && \
|
||||
if [ -e /dev/fuse ] ; \
|
||||
then /bin/fusermount -u project | true && /bin/rmdir project && /bin/mv project.u project ; \
|
||||
fi
|
||||
|
||||
# export build output
|
||||
FROM scratch AS export-stage
|
||||
COPY --from=build-stage /home/builder/project/oeffi/build/outputs/apk/release/oeffi-release-unsigned.apk /
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.4'
|
||||
classpath 'net.sf.proguard:proguard-gradle:6.0.3'
|
||||
classpath 'net.sf.proguard:proguard-gradle:6.2.2'
|
||||
classpath('fr.avianey.androidsvgdrawable:gradle-plugin:3.0.2') {
|
||||
exclude group: 'xerces'
|
||||
}
|
||||
|
|
|
@ -18,22 +18,21 @@
|
|||
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="de.schildbach.oeffi"
|
||||
android:versionCode="120015"
|
||||
android:versionName="12.0.15">
|
||||
android:versionCode="130011"
|
||||
android:versionName="13.0.11">
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="21"
|
||||
android:targetSdkVersion="30" />
|
||||
android:minSdkVersion="24"
|
||||
android:targetSdkVersion="35" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
|
||||
|
||||
<uses-feature
|
||||
|
@ -61,6 +60,7 @@
|
|||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_oeffi_stations_color_48dp"
|
||||
android:label="@string/app_name"
|
||||
android:localeConfig="@xml/locale_config"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:theme="@style/My.Theme">
|
||||
|
||||
|
@ -86,6 +86,7 @@
|
|||
|
||||
<activity
|
||||
android:name=".stations.StationsActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="keyboard|keyboardHidden"
|
||||
android:label="@string/stations_icon_label"
|
||||
android:launchMode="singleTop"
|
||||
|
@ -97,12 +98,6 @@
|
|||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
<!-- thrown by google maps when starting navigation -->
|
||||
<intent-filter android:label="@string/stations_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="google.navigation" />
|
||||
</intent-filter>
|
||||
<!-- thrown by google now gesture -->
|
||||
<intent-filter android:label="@string/stations_intentfilter_title">
|
||||
<action android:name="android.intent.action.ASSIST" />
|
||||
|
@ -118,107 +113,11 @@
|
|||
|
||||
<activity
|
||||
android:name=".stations.StationDetailsActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="keyboard|keyboardHidden"
|
||||
android:label="@string/station_details_activity_title"
|
||||
android:taskAffinity="de.schildbach.oeffi.stations">
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:host="oeffi.schildbach.de" />
|
||||
<data android:pathPrefix="/station/" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="qr.bvg.de" />
|
||||
<data android:pathPrefix="/h" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="mobil.s-bahn-berlin.de" />
|
||||
<data android:path="/" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="wap.rmv.de" />
|
||||
<data android:pathPrefix="/mobil/tag/request.do" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="m.vrn.de" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="www.mvg-live.de" />
|
||||
<data android:pathPrefix="/qr" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="www.rheinbahn.de" />
|
||||
<data android:pathPrefix="/QRBarcode/HS" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="mobil.vvs.de" />
|
||||
<data android:pathPrefix="/mob/DMR" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="m.qando.at" />
|
||||
<data android:pathPrefix="/qr" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".stations.DecodeForeignActivity"
|
||||
android:launchMode="singleInstance"
|
||||
android:taskAffinity="de.schildbach.oeffi.stations"
|
||||
android:theme="@style/My.Theme.Translucent">
|
||||
<intent-filter android:label="@string/stations_station_details_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:host="www.rmv.de" />
|
||||
<data android:pathPrefix="/t/d" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
android:showWhenLocked="true" />
|
||||
|
||||
<activity
|
||||
android:name=".stations.FavoriteStationsActivity"
|
||||
|
@ -236,10 +135,20 @@
|
|||
|
||||
<receiver
|
||||
android:name=".stations.NearestFavoriteStationWidgetProvider"
|
||||
android:exported="false"
|
||||
android:label="@string/nearest_favorite_station_widget_label">
|
||||
<intent-filter>
|
||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.appwidget.provider"
|
||||
android:resource="@xml/nearest_favorite_station_widget" />
|
||||
|
@ -257,6 +166,7 @@
|
|||
|
||||
<activity
|
||||
android:name=".directions.DirectionsActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="keyboard|keyboardHidden"
|
||||
android:icon="@mipmap/ic_oeffi_directions_color_48dp"
|
||||
android:label="@string/directions_icon_label"
|
||||
|
@ -271,215 +181,9 @@
|
|||
<intent-filter android:label="@string/directions_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="geo" />
|
||||
</intent-filter>
|
||||
<!-- thrown by google maps when starting navigation -->
|
||||
<intent-filter android:label="@string/directions_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="google.navigation" />
|
||||
</intent-filter>
|
||||
<!-- thrown by google now, and google calendar for plain addresses -->
|
||||
<intent-filter android:label="@string/directions_intentfilter_title">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="http" />
|
||||
<data android:scheme="https" />
|
||||
<data android:host="maps.google.com" />
|
||||
<data android:host="maps.google.cat" />
|
||||
<data android:host="maps.google.it.ao" />
|
||||
<data android:host="mapy.google.pl" />
|
||||
<data android:host="local.google.com" />
|
||||
<!-- maps.google.co.tld -->
|
||||
<data android:host="maps.google.co.ao" />
|
||||
<data android:host="maps.google.co.bw" />
|
||||
<data android:host="maps.google.co.ck" />
|
||||
<data android:host="maps.google.co.cr" />
|
||||
<data android:host="maps.google.co.id" />
|
||||
<data android:host="maps.google.co.il" />
|
||||
<data android:host="maps.google.co.in" />
|
||||
<data android:host="maps.google.co.jp" />
|
||||
<data android:host="maps.google.co.ke" />
|
||||
<data android:host="maps.google.co.kr" />
|
||||
<data android:host="maps.google.co.ls" />
|
||||
<data android:host="maps.google.co.ma" />
|
||||
<data android:host="maps.google.co.mz" />
|
||||
<data android:host="maps.google.co.nz" />
|
||||
<data android:host="maps.google.co.th" />
|
||||
<data android:host="maps.google.co.tz" />
|
||||
<data android:host="maps.google.co.ug" />
|
||||
<data android:host="maps.google.co.uk" />
|
||||
<data android:host="maps.google.co.ve" />
|
||||
<data android:host="maps.google.co.vi" />
|
||||
<data android:host="maps.google.co.za" />
|
||||
<data android:host="maps.google.co.zm" />
|
||||
<data android:host="maps.google.co.zw" />
|
||||
<!-- maps.google.com.tld -->
|
||||
<data android:host="maps.google.com.ag" />
|
||||
<data android:host="maps.google.com.ai" />
|
||||
<data android:host="maps.google.com.ar" />
|
||||
<data android:host="maps.google.com.au" />
|
||||
<data android:host="maps.google.com.bd" />
|
||||
<data android:host="maps.google.com.bh" />
|
||||
<data android:host="maps.google.com.bn" />
|
||||
<data android:host="maps.google.com.bo" />
|
||||
<data android:host="maps.google.com.br" />
|
||||
<data android:host="maps.google.com.bz" />
|
||||
<data android:host="maps.google.com.co" />
|
||||
<data android:host="maps.google.com.cu" />
|
||||
<data android:host="maps.google.com.do" />
|
||||
<data android:host="maps.google.com.ec" />
|
||||
<data android:host="maps.google.com.eg" />
|
||||
<data android:host="maps.google.com.et" />
|
||||
<data android:host="maps.google.com.fj" />
|
||||
<data android:host="maps.google.com.gh" />
|
||||
<data android:host="maps.google.com.gi" />
|
||||
<data android:host="maps.google.com.gt" />
|
||||
<data android:host="maps.google.com.hk" />
|
||||
<data android:host="maps.google.com.iq" />
|
||||
<data android:host="maps.google.com.jm" />
|
||||
<data android:host="maps.google.com.kh" />
|
||||
<data android:host="maps.google.com.kw" />
|
||||
<data android:host="maps.google.com.lb" />
|
||||
<data android:host="maps.google.com.lv" />
|
||||
<data android:host="maps.google.com.ly" />
|
||||
<data android:host="maps.google.com.mm" />
|
||||
<data android:host="maps.google.com.mt" />
|
||||
<data android:host="maps.google.com.mx" />
|
||||
<data android:host="maps.google.com.my" />
|
||||
<data android:host="maps.google.com.na" />
|
||||
<data android:host="maps.google.com.ng" />
|
||||
<data android:host="maps.google.com.ni" />
|
||||
<data android:host="maps.google.com.np" />
|
||||
<data android:host="maps.google.com.om" />
|
||||
<data android:host="maps.google.com.pa" />
|
||||
<data android:host="maps.google.com.pe" />
|
||||
<data android:host="maps.google.com.pg" />
|
||||
<data android:host="maps.google.com.ph" />
|
||||
<data android:host="maps.google.com.pr" />
|
||||
<data android:host="maps.google.com.py" />
|
||||
<data android:host="maps.google.com.qa" />
|
||||
<data android:host="maps.google.com.sa" />
|
||||
<data android:host="maps.google.com.sb" />
|
||||
<data android:host="maps.google.com.sg" />
|
||||
<data android:host="maps.google.com.sl" />
|
||||
<data android:host="maps.google.com.sv" />
|
||||
<data android:host="maps.google.com.tr" />
|
||||
<data android:host="maps.google.com.tw" />
|
||||
<data android:host="maps.google.com.ua" />
|
||||
<data android:host="maps.google.com.uy" />
|
||||
<data android:host="maps.google.com.vc" />
|
||||
<!-- maps.google.tld -->
|
||||
<data android:host="maps.google.ad" />
|
||||
<data android:host="maps.google.ae" />
|
||||
<data android:host="maps.google.as" />
|
||||
<data android:host="maps.google.at" />
|
||||
<data android:host="maps.google.ba" />
|
||||
<data android:host="maps.google.be" />
|
||||
<data android:host="maps.google.bf" />
|
||||
<data android:host="maps.google.bg" />
|
||||
<data android:host="maps.google.bi" />
|
||||
<data android:host="maps.google.bj" />
|
||||
<data android:host="maps.google.bs" />
|
||||
<data android:host="maps.google.bt" />
|
||||
<data android:host="maps.google.by" />
|
||||
<data android:host="maps.google.ca" />
|
||||
<data android:host="maps.google.cd" />
|
||||
<data android:host="maps.google.cf" />
|
||||
<data android:host="maps.google.cg" />
|
||||
<data android:host="maps.google.ch" />
|
||||
<data android:host="maps.google.ci" />
|
||||
<data android:host="maps.google.cl" />
|
||||
<data android:host="maps.google.cm" />
|
||||
<data android:host="maps.google.cn" />
|
||||
<data android:host="maps.google.cv" />
|
||||
<data android:host="maps.google.cz" />
|
||||
<data android:host="maps.google.de" />
|
||||
<data android:host="maps.google.dj" />
|
||||
<data android:host="maps.google.dk" />
|
||||
<data android:host="maps.google.dm" />
|
||||
<data android:host="maps.google.dz" />
|
||||
<data android:host="maps.google.ee" />
|
||||
<data android:host="maps.google.es" />
|
||||
<data android:host="maps.google.fi" />
|
||||
<data android:host="maps.google.fm" />
|
||||
<data android:host="maps.google.fr" />
|
||||
<data android:host="maps.google.ga" />
|
||||
<data android:host="maps.google.ge" />
|
||||
<data android:host="maps.google.gg" />
|
||||
<data android:host="maps.google.gl" />
|
||||
<data android:host="maps.google.gm" />
|
||||
<data android:host="maps.google.gp" />
|
||||
<data android:host="maps.google.gr" />
|
||||
<data android:host="maps.google.gy" />
|
||||
<data android:host="maps.google.hk" />
|
||||
<data android:host="maps.google.hn" />
|
||||
<data android:host="maps.google.hr" />
|
||||
<data android:host="maps.google.ht" />
|
||||
<data android:host="maps.google.hu" />
|
||||
<data android:host="maps.google.ie" />
|
||||
<data android:host="maps.google.im" />
|
||||
<data android:host="maps.google.iq" />
|
||||
<data android:host="maps.google.is" />
|
||||
<data android:host="maps.google.it" />
|
||||
<data android:host="maps.google.je" />
|
||||
<data android:host="maps.google.jo" />
|
||||
<data android:host="maps.google.jp" />
|
||||
<data android:host="maps.google.kg" />
|
||||
<data android:host="maps.google.ki" />
|
||||
<data android:host="maps.google.kz" />
|
||||
<data android:host="maps.google.la" />
|
||||
<data android:host="maps.google.li" />
|
||||
<data android:host="maps.google.lk" />
|
||||
<data android:host="maps.google.lt" />
|
||||
<data android:host="maps.google.lu" />
|
||||
<data android:host="maps.google.lv" />
|
||||
<data android:host="maps.google.md" />
|
||||
<data android:host="maps.google.mg" />
|
||||
<data android:host="maps.google.mk" />
|
||||
<data android:host="maps.google.ml" />
|
||||
<data android:host="maps.google.mn" />
|
||||
<data android:host="maps.google.ms" />
|
||||
<data android:host="maps.google.mt" />
|
||||
<data android:host="maps.google.mu" />
|
||||
<data android:host="maps.google.mv" />
|
||||
<data android:host="maps.google.mw" />
|
||||
<data android:host="maps.google.ne" />
|
||||
<data android:host="maps.google.nf" />
|
||||
<data android:host="maps.google.ng" />
|
||||
<data android:host="maps.google.nl" />
|
||||
<data android:host="maps.google.no" />
|
||||
<data android:host="maps.google.nr" />
|
||||
<data android:host="maps.google.nu" />
|
||||
<data android:host="maps.google.pl" />
|
||||
<data android:host="maps.google.pn" />
|
||||
<data android:host="maps.google.pt" />
|
||||
<data android:host="maps.google.ro" />
|
||||
<data android:host="maps.google.rs" />
|
||||
<data android:host="maps.google.ru" />
|
||||
<data android:host="maps.google.rw" />
|
||||
<data android:host="maps.google.sc" />
|
||||
<data android:host="maps.google.se" />
|
||||
<data android:host="maps.google.sh" />
|
||||
<data android:host="maps.google.si" />
|
||||
<data android:host="maps.google.sk" />
|
||||
<data android:host="maps.google.sm" />
|
||||
<data android:host="maps.google.sn" />
|
||||
<data android:host="maps.google.so" />
|
||||
<data android:host="maps.google.st" />
|
||||
<data android:host="maps.google.td" />
|
||||
<data android:host="maps.google.tg" />
|
||||
<data android:host="maps.google.tk" />
|
||||
<data android:host="maps.google.ti" />
|
||||
<data android:host="maps.google.tl" />
|
||||
<data android:host="maps.google.tn" />
|
||||
<data android:host="maps.google.to" />
|
||||
<data android:host="maps.google.tt" />
|
||||
<data android:host="maps.google.vg" />
|
||||
<data android:host="maps.google.vu" />
|
||||
<data android:host="maps.google.ws" />
|
||||
<data android:pathPrefix="/" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
|
@ -492,10 +196,12 @@
|
|||
android:name=".directions.TripDetailsActivity"
|
||||
android:configChanges="keyboard|keyboardHidden"
|
||||
android:label="@string/trip_details_title"
|
||||
android:taskAffinity="de.schildbach.oeffi.directions" />
|
||||
android:taskAffinity="de.schildbach.oeffi.directions"
|
||||
android:showWhenLocked="true" />
|
||||
|
||||
<activity
|
||||
android:name=".directions.DirectionsShortcutActivity"
|
||||
android:exported="true"
|
||||
android:launchMode="singleInstance"
|
||||
android:taskAffinity="de.schildbach.oeffi.directions"
|
||||
android:theme="@style/My.Theme.Translucent">
|
||||
|
@ -511,6 +217,7 @@
|
|||
|
||||
<activity
|
||||
android:name=".plans.PlansPickerActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="keyboard|keyboardHidden"
|
||||
android:icon="@mipmap/ic_oeffi_plans_color_48dp"
|
||||
android:label="@string/plans_icon_label"
|
||||
|
@ -533,10 +240,12 @@
|
|||
|
||||
<activity
|
||||
android:name=".plans.PlanActivity"
|
||||
android:exported="true"
|
||||
android:configChanges="keyboard|keyboardHidden"
|
||||
android:launchMode="singleTop"
|
||||
android:taskAffinity="de.schildbach.oeffi.plans"
|
||||
android:theme="@style/My.Theme.Fullscreen">
|
||||
android:theme="@style/My.Theme.Fullscreen"
|
||||
android:showWhenLocked="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.SEARCH" />
|
||||
</intent-filter>
|
||||
|
@ -554,4 +263,7 @@
|
|||
android:exported="false" />
|
||||
</application>
|
||||
|
||||
<!-- remove unnecessary merged nodes -->
|
||||
<permission android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" tools:node="remove" />
|
||||
<uses-permission android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" tools:node="remove" />
|
||||
</manifest>
|
||||
|
|
|
@ -1,4 +1,68 @@
|
|||
v12.0.12-v12.0.15
|
||||
v13.0.11
|
||||
|
||||
* Add region again: Poland (PKP)
|
||||
|
||||
v13.0.4-v13.0.10
|
||||
|
||||
* Target Android 15.
|
||||
|
||||
v13.0.3
|
||||
|
||||
* Remove regions: Czech Republic, Italy, Paris, Spain, Nicaragua
|
||||
|
||||
v13.0.2
|
||||
|
||||
* Remove region: Finland
|
||||
|
||||
v13.0-v13.0.1
|
||||
|
||||
* Running the app now requires Android 7.0 (Nougat) or higher.
|
||||
* Building the app now requires OpenJDK 17.
|
||||
* Remove `google` flavor.
|
||||
* Git: rename `master` to `main` branch.
|
||||
|
||||
v12.1.18-v12.1.21
|
||||
|
||||
* Remove region: Belgium (SNCB)
|
||||
|
||||
v12.1.15-v12.1.17
|
||||
|
||||
* Migrate region Augsburg from EFA to Hafas
|
||||
|
||||
v12.1.7-v12.1.14
|
||||
|
||||
* Merge regions Oberelbe (VVO) and Mittelsachsen (VMS) into Saxony
|
||||
|
||||
v12.1.3-v12.1.6
|
||||
|
||||
* Remove region: Poland (PKP)
|
||||
|
||||
v12.1.1-v12.1.2
|
||||
|
||||
* Use activity result API for permission requests, picking contacts and picking favorite stations.
|
||||
|
||||
v12.1
|
||||
|
||||
* Enable per-app locale selection on Android 13 (and higher).
|
||||
* Drop unnecessary permissions.
|
||||
|
||||
v12.0.25
|
||||
|
||||
* Target Android 13.
|
||||
|
||||
v12.0.23-v12.0.24
|
||||
|
||||
* Migrate periodic app-widget refresh from JobIntentService to JobScheduler
|
||||
|
||||
v12.0.21-v12.0.22
|
||||
|
||||
* Target Android 12.
|
||||
|
||||
v12.0.19-v12.0.20
|
||||
|
||||
* Fix showing a location on an external maps app.
|
||||
|
||||
v12.0.12-v12.0.18
|
||||
|
||||
* Remove region: Schweizerische Bundesbahnen (SBB)
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ DB|de-DE|DE
|
|||
BVG|de-DE|Brandenburg;Berlin
|
||||
VBB|de-DE|Brandenburg
|
||||
BAYERN|de-DE|Bayern;Würzburg;Regensburg
|
||||
AVV|de-DE|Augsburg
|
||||
AVV_AUGSBURG|de-DE|Augsburg
|
||||
MVV|de-DE|Bayern;München
|
||||
INVG|de-DE|Ingolstadt
|
||||
VGN|de-DE|Nürnberg;Fürth;Erlangen
|
||||
|
@ -19,8 +19,7 @@ SH|de-DE|Schleswig-Holstein;Kiel;Lübeck;Hamburg
|
|||
GVH|de-DE|Niedersachsen;Hannover;Hamburg
|
||||
BSVAG|de-DE|Braunschweig;Wolfsburg
|
||||
VBN|de-DE|Niedersachsen;Hamburg;Bremen;Bremerhaven;Oldenburg (Oldenburg);Osnabrück;Göttingen;Rostock
|
||||
VVO|de-DE|Sachsen;Dresden
|
||||
VMS|de-DE|Mittelsachsen;Chemnitz
|
||||
VVO|de-DE|Sachsen;Dresden;Mittelsachsen;Chemnitz
|
||||
NASA|de-DE|Sachsen;Leipzig;Sachsen-Anhalt;Magdeburg;Halle
|
||||
VMT|de-DE|Thüringen;Mittelthüringen;Erfurt;Jena;Gera;Weimar;Gotha
|
||||
VRR|de-DE|Nordrhein-Westfalen;Essen;Dortmund;Düsseldorf;Münster;Paderborn;Höxter;Bielefeld
|
||||
|
@ -46,25 +45,10 @@ VVT|de-AT|Tirol|disabled
|
|||
SVV|de-AT|Salzburg|disabled
|
||||
VMOBIL|de-AT|Vorarlberg;Bregenz|disabled
|
||||
|
||||
# CZ
|
||||
CZECH_REPUBLIC|cs-CZ|Tschechien;Praha;Prag|beta
|
||||
|
||||
# CH
|
||||
VBL|de-CH|Luzern
|
||||
ZVV|de-CH|Zürich
|
||||
|
||||
# IT
|
||||
IT|it-IT|IT|alpha
|
||||
|
||||
# FR
|
||||
PARIS|fr-FR|FR|alpha
|
||||
|
||||
# ES
|
||||
SPAIN|es-ES|ES|alpha
|
||||
|
||||
# BE
|
||||
SNCB|be-BE|BE|alpha
|
||||
|
||||
# LU
|
||||
LU|lb-LU|LU;Luxemburg
|
||||
|
||||
|
@ -77,16 +61,10 @@ DSB|da-DK|DK;København
|
|||
# SE
|
||||
SE|sv-SE|SE;Stockholm
|
||||
|
||||
# FI
|
||||
FINLAND|fi-FI|FI;Helsinki|beta
|
||||
|
||||
# GB
|
||||
TLEM|en-UK|GB;Greater London;Derbyshire;Leicestershire;Rutland;Northamptonshire;Nottinghamshire;Lincolnshire;Berkshire;Buckinghamshire;East Sussex;Hampshire;Isle of Wight;Kent;Oxfordshire;Surrey;West Sussex;Essex;Hertfordshire;Bedfordshire;Cambridgeshire;Norfolk;Suffolk;Somerset;Gloucestershire;Wiltshire;Dorset;Devon;Cornwall;West Devon;Stowford;Eastleigh;Swindon;Gloucester;Plymouth;Torbay;Bournemouth;Poole;Birmingham
|
||||
MERSEY|en-UK|GB;Liverpool|beta
|
||||
|
||||
# IE
|
||||
TFI|ga-IE|IE;Dublin;GB;Belfast
|
||||
|
||||
# PL
|
||||
PL|pl-PL|PL;Warschau
|
||||
|
||||
|
@ -101,6 +79,3 @@ CMTA|us-US|US;Texas;Austin|beta
|
|||
# AU
|
||||
SYDNEY|en-AU|AU;New South Wales;Sydney
|
||||
MET|en-AU|AU;Victoria;Melbourne|disabled
|
||||
|
||||
# NI
|
||||
NICARAGUA|es-NI|NI;Managua|beta
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
# de
|
||||
|
||||
berlin_bsu_ab|52.520134,13.388018|2020-10-31|Berlin S+U-Bahn-Netz (AB)|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_bsu_abc|52.520134,13.388018|2019-10-31|Berlin S+U-Bahn-Netz (ABC)|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_tram|52.521152,13.412832|2020-04-14|Berlin Tram-Netz|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_bus|52.5071378,13.3318680|2019-12-15|Berlin Bus-Netz|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_nacht|52.520134,13.388018|2020-10-31|Berlin Nachtverkehr (geografisch)|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_bsu_ab|52.520134,13.388018|2022-12-11|Berlin S+U-Bahn-Netz (AB)|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_bsu_abc|52.520134,13.388018|2022-12-11|Berlin S+U-Bahn-Netz (ABC)|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_tram|52.521152,13.412832|2022-12-16|Berlin Tram-Netz|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_bus|52.5071378,13.3318680|2022-12-09|Berlin Bus-Netz|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_nacht|52.520134,13.388018|2022-12-09|Berlin Nachtverkehr (geografisch)|Berliner Verkehrsbetriebe||BVG
|
||||
berlin_transitmap|52.520134,13.388018|2018-12-09|New Berlin rapid transit route map|berlintransitmap.de
|
||||
# berlin_anbindung_ber|52.363127,13.50498|2011-10|Berlin Brandenburg Flughafen Anbindung|Robert Aehnelt, Creative Commons|https://upload.wikimedia.org/wikipedia/commons/d/d3/Anbindung_BER.png
|
||||
berlin_anbindung_ber|52.363127,13.50498|2020-11|BER (Flughafen Berlin Brandenburg) Anbindung|Robert Aehnelt, Creative Commons|https://upload.wikimedia.org/wikipedia/commons/e/e0/BER_Anbindung_2020.jpg
|
||||
brandenburg_regionalverkehr|52.525578,13.369523|2019-12-15|Brandenburg Regionalverkehr|Verkehrsverbund Berlin-Brandenburg||VBB
|
||||
potsdam_tag|52.390931,13.067171|2019-12-15|Potsdam Tagesliniennetz|Verkehrsverbund Berlin-Brandenburg||VBB
|
||||
potsdam_nacht|52.390931,13.067171|2019-12-15|Potsdam Nachtliniennetz|Verkehrsverbund Berlin-Brandenburg||VBB
|
||||
|
@ -23,6 +23,7 @@ stettin|53.4182413,14.5494069|2019-12-09|Stettin|Zarząd Dróg i Transportu Miej
|
|||
dresden|51.050961,13.733239|2021-01-25|Dresden Liniennetz|Dresdner Verkehrsbetriebe AG
|
||||
dresden_rolli|51.050961,13.733239|2020|Dresden für mobilitätseingeschränkte Personen|Dresdner Verkehrsbetriebe AG
|
||||
dresden_nacht|51.050961,13.733239|2021-01-25|Dresden Nachtverkehr|Verkehrsverbund Oberelbe||VVO
|
||||
dresden_tarif|51.050961,13.733239|2020-12-13|Dresden Tarifzonen|Verkehrsverbund Oberelbe||VVO
|
||||
chemnitz_tag|50.836227,12.919122|2018-02-26|Chemnitz Netzplan|Chemnitzer Verkehrs-AG
|
||||
chemnitz_nacht|50.836227,12.919122|2017-12-10|Chemnitz Nachtnetz|Chemnitzer Verkehrs-AG
|
||||
sachsen_spnv|50.925093,12.775949|2020-12-13|Sachsen SPNV-Netz
|
||||
|
@ -31,6 +32,7 @@ leipzig_tag|51.345476,12.379382|2020-11-18|Leipzig Linien Tag|Leipziger Verkehrs
|
|||
leipzig_nacht|51.345476,12.379382|2020-11-18|Leipzig Linien Nacht|Leipziger Verkehrsbetriebe GmbH
|
||||
halle_tag|51.477347,11.985263|2020-08-27|Halle Linien Tag|SWH/HAVAG
|
||||
halle_nacht|51.477347,11.985263|2020-08-27|Halle Linien Nacht|SWH/HAVAG
|
||||
jena|50.9248984,11.587666|2024|Jena|Jenaer Nahverkehr GmbH
|
||||
muenchen_schnellbahn|48.140377,11.560643|2019-12|München Schnellbahn|MVV
|
||||
muenchen_tram_metrobus|48.140377,11.560643|2019-12-15|München Tram/MetroBus|MVV/MVG
|
||||
muenchen_nacht|48.140377,11.560643|2019-12-15|München Nachtnetz|MVG
|
||||
|
@ -41,10 +43,10 @@ augsburg|48.364936,10.893713|2018-12|Augsburg Innenraum|AVV GmbH
|
|||
augsburg_nachtbus|48.364936,10.893713|2018-12|Augsburg Nachtbus|AVV GmbH
|
||||
ulm_stadt|48.398610,9.983322|2018-12|Ulm / Neu-Ulm Stadtnetz|Donau-Iller-Nahverkehrsverbund GmbH
|
||||
ulm_regional|48.398610,9.983322|2018-11-02|Ulm Regionalnetz|Donau-Iller-Nahverkehrsverbund GmbH
|
||||
nuernberg_gesamtraum|49.445719,11.082618|2018-01-01|Nürnberg Schienennetz Gesamtraum|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
nuernberg_verkehrsnetz|49.445719,11.082618|2019-12-01|Nürnberg, Fürth, Stein Verkehrsnetz|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
nuernberg_schiene|49.445719,11.082618|2019-12-01|Nürnberg, Fürth Schienennetz|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
nuernberg_nightliner|49.445719,11.082618|2019-12-01|Nürnberg, Fürth Nightliner|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
nuernberg_gesamtraum|49.445719,11.082618|2024-01-01|Nürnberg Schienennetz Gesamtraum|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
nuernberg_verkehrsnetz|49.445719,11.082618|2023-12-10|Nürnberg-Fürth Liniennetz|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
nuernberg_schiene|49.445719,11.082618|2023-12-10|Nürnberg-Fürth Schienennetz|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
nuernberg_nightliner|49.445719,11.082618|2023-12|Nürnberg-Fürth Nightliner|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
fuerth_verkehrsnetz|49.469832,10.990178|2019-12-01|Fürth Verkehrsnetz|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
fuerth_nightliner|49.469832,10.990178|2016-12-11|Fürth Nightliner|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
erlangen_verkehrsnetz|49.595851,11.001701|2019-12-01|Erlangen Verkehrsnetz|Verkehrsverbund Großraum Nürnberg||VGN
|
||||
|
@ -58,25 +60,26 @@ regensburg_nacht|49.011489,12.09971|2018-04-14|Regensburg Nachtbus|Regensburger
|
|||
bremen|53.08319,8.81360|2020-03|Bremen Liniennetz|BSAG
|
||||
bremen_nacht|53.08319,8.81360||Bremen Nachtnetz|BSAG
|
||||
bremen_stadt|53.08319,8.81360|2020-02|Bremen Stadtnetz (geografisch)|BSAG
|
||||
hamburg_usar|53.552946,10.006782|2020-12-13|Hamburg Schnellbahn/Regional|HVV
|
||||
hamburg_metrobus_gross|53.552946,10.006782|2020-12-13|Hamburg MetroBus Großbereich|HVV
|
||||
hamburg_region|53.552946,10.006782|2019-12-15|Hamburg Regionalverkehr|HVV
|
||||
kiel_liniennetz|54.313282,10.132341|2019-12|Kiel Liniennetz|KVG
|
||||
kiel_nacht|54.313282,10.132341|2019-12|Kiel Nachtliniennetz|KVG
|
||||
hamburg_usar|53.552946,10.006782|2023-12-10|Hamburg Schnellbahn/Regional|HVV
|
||||
hamburg_metrobus_gross|53.552946,10.006782|2023-12-10|Hamburg MetroBus Liniennetz|HVV
|
||||
hamburg_region|53.552946,10.006782|2023-12-10|Hamburg Regionalverkehr|HVV
|
||||
hamburg_weiss_bus|53.552946,10.006782|2024-01-08|Hamburg Busliniennetz|Lucas Weiss
|
||||
kiel_liniennetz|54.313282,10.132341|2023-12|Kiel Liniennetz|KVG
|
||||
kiel_nacht|54.313282,10.132341|2022-12|Kiel Nachtliniennetz|KVG
|
||||
luebeck_region|53.858795,10.664646|2018-12-09|Lübeck Liniennetz Region|LVG, nah.sh, Stadtverkehr Lübeck||SH
|
||||
rostock_vvw_liniennetz|54.078139,12.131724|2019-01-07|Rostock Liniennetz|Verkehrsverbund Warnow
|
||||
rostock_vvw_region|54.078139,12.131724|2019-01-07|Rostock Region|Verkehrsverbund Warnow
|
||||
rostock_region|54.078139,12.131724|2021-01-04|Rostock und Umgebung|Lucas Weiss, CC-BY-NC-SA 4.0
|
||||
rostock_vvw_liniennetz|54.078139,12.131724|2023-08-28|Rostock Liniennetz|Verkehrsverbund Warnow
|
||||
rostock_vvw_region|54.078139,12.131724|2023-08-28|Rostock Region|Verkehrsverbund Warnow
|
||||
rostock_region|54.078139,12.131724|2023-12-10|Rostock und Umgebung|Lucas Weiss, CC-BY-NC-SA 4.0
|
||||
wismar|53.903943,11.391928||Wismar Stadtverkehr|NAHBUS Nordwestmecklenburg GmbH
|
||||
nordwestmecklenburg|53.903943,11.391928|2016-03-14|Nordwestmecklenburg Busnetz|NAHBUS Nordwestmecklenburg GmbH
|
||||
osnabrueck|52.272832,8.061726|2018-08-09|Osnabrück Liniennetz|Stadtwerke Osnabrück
|
||||
osnabrueck_nacht|52.272832,8.061726|2018-08-09|Osnabrück NachtBus-Netz|Stadtwerke Osnabrück
|
||||
stuttgart_verbund|48.784068,9.181713|2018-12|Stuttgart Verbund-Liniennetz|Verkehrs- und Tarifverbund Stuttgart GmbH
|
||||
stuttgart_nacht|48.77861,9.179803|2018-12|Stuttgart Nachtverkehr|Verkehrs- und Tarifverbund Stuttgart GmbH
|
||||
stuttgart_verbund|48.784068,9.181713|2023-12|Stuttgart Verbund-Liniennetz|Verkehrs- und Tarifverbund Stuttgart GmbH
|
||||
stuttgart_nacht|48.77861,9.179803|2023-12|Stuttgart Nachtverkehr|Verkehrs- und Tarifverbund Stuttgart GmbH
|
||||
ringzug|48.113621,8.660603|2013-08|Ringzug|Zweckverband Ringzug
|
||||
hannover_stadtbahn|52.376715,9.741168|2018-12|Hannover Stadtbahnnetz|GVH
|
||||
hannover_bus|52.376715,9.741168|2018-12|Hannover Busnetz|GVH
|
||||
hannover_regional|52.376715,9.741168|2018-12|Hannover Regional- und S-Bahn-Linien|GVH
|
||||
hannover_stadtbahn|52.376715,9.741168|2023-12-10|Hannover Stadtbahnnetz|GVH
|
||||
hannover_bus|52.376715,9.741168|2023-12-10|Hannover Busnetz|GVH
|
||||
hannover_regional|52.376715,9.741168|2023-12-10|Hannover Regional- und S-Bahn-Linien|GVH
|
||||
celle_stadt|52.620411,10.059814|2019-01|Celle Liniennetz Stadt|CeBus
|
||||
celle_region|52.620411,10.059814|2018-01|Celle Liniennetz Region|CeBus
|
||||
goettingen|51.536290,9.926981|2019-12-15|Göttingen Liniennetz|Göttinger Verkehrsbetriebe GmbH
|
||||
|
@ -87,16 +90,24 @@ bielefeld_netz|52.029241,8.532835|2018-06|Bielefeld Netzplan (geografisch)|moBie
|
|||
essen_schiene|51.451355,7.014793|2015-06-14|Essen SchienenNetz|EVAG
|
||||
essen_tag|51.451355,7.014793|2015-06-14|Essen TagNetz|EVAG
|
||||
essen_nacht|51.451355,7.014793|2013-06-09|Essen NachtNetz|EVAG
|
||||
krefeld_stadt|51.323714,6.565800|2013-06|Krefeld Liniennetz Stadt|SWK/VRR
|
||||
krefeld_stadt_nacht|51.323714,6.565800|2013-06|Krefeld Nachtnetz|SWK/VRR
|
||||
dortmund_schiene|51.517843,7.459272|2023-01|Dortmund Schienennetz|DSW21
|
||||
dortmund_tag|51.517843,7.459272|2023-12|Dortmund Netzplan Tag|DSW21
|
||||
dortmund_nacht|51.517843,7.459272|2021-01|Dortmund Netzplan Nacht|DSW21
|
||||
krefeld_stadt|51.323714,6.565800|2021-05|Krefeld Liniennetz Stadt|SWK/VRR
|
||||
krefeld_stadt_nacht|51.323714,6.565800|2021-05|Krefeld Nachtnetz|SWK/VRR
|
||||
frankfurt_liniennetz|50.106318,8.662139|2020-12-13|Frankfurt am Main Liniennetz|traffiQ
|
||||
frankfurt_flughafen_bus|50.037936,8.559958|2020-12-13|Frankfurt Flughafen Buslinien|traffiQ
|
||||
gelsenkirchen_linienplan_tag|51.504768,7.102298|2023-01|Gelsenkirchen Linienplan Tag|Vestische
|
||||
gelsenkirchen_linienplan_nacht|51.504768,7.102298|2023-01|Gelsenkirchen Linienplan Nacht|Vestische
|
||||
recklinghausen_linienplan|51.616096,7.203273|2023-06|Recklinghausen Linienplan|Vestische
|
||||
waltrop_linienplan|51.622799,7.390409|2022-08|Waltrop Linienplan|Vestische
|
||||
rmv_schnellbahn|50.106318,8.662139|2020-12-13|Rhein-Main Schnellbahn|RMV
|
||||
rmv_regional|50.106318,8.662139|2020-12-13|Rhein-Main Regional|RMV
|
||||
rmv_nacht|50.106318,8.662139|2020-12-13|Rhein-Main Nachtnetz|RMV
|
||||
mainz|50.001395,8.258818|2019-12-15|Mainz Tag|Mainzer Verkehrsgesellschaft mbH
|
||||
mainz_nacht|50.001395,8.258818|2019-12-15|Mainz Nacht|Mainzer Verkehrsgesellschaft mbH
|
||||
koeln_schnellverkehr|50.943579,6.95796|2019-12-15|Köln Schnellverkehr|Verkehrsverbund Rhein-Sieg GmbH
|
||||
koeln_stadtbahn|50.943579,6.95796|2024-04-02|Köln Stadtbahn|Kölner Verkehrs-Betriebe AG
|
||||
koeln_bus|50.943579,6.95796|2019-12-15|Köln Busnetz|Verkehrsverbund Rhein-Sieg GmbH
|
||||
bonn_schnellverkehr|50.732784,7.096447|2019-12-15|Bonn Schnellverkehr|Verkehrsverbund Rhein-Sieg GmbH
|
||||
bonn_bus|50.732784,7.096447|2019-12-15|Bonn Busnetz|Verkehrsverbund Rhein-Sieg GmbH
|
||||
|
@ -104,29 +115,33 @@ leverkusen_bus|51.036197,6.994385|2019-12-15|Leverkusen Busnetz|Verkehrsverbund
|
|||
nrw_regio|51.429807,6.775253|2016-12|NRW Busse & Bahnen|VRS
|
||||
aachen_schnellverkehr|50.768399,6.090705|2018-12|Aachen Schnellverkehr|Aachener Verkehrsverbund GmbH||AVV_AACHEN
|
||||
aachen_region|50.768399,6.090705|2018-12|Aachen Region, Bus und Bahn|Aachener Verkehrsverbund GmbH||AVV_AACHEN
|
||||
darmstadt|49.872582,8.630916|2020-12-13|Darmstadt Stadt|Darmstadt-Dieburger Nahverkehrsorganisation
|
||||
darmstadt_nacht|49.872582,8.630916|2020-12-13|Darmstadt NightLiner|Darmstadt-Dieburger Nahverkehrsorganisation
|
||||
darmstadt_region|49.872582,8.630916|2020-12-13|Darmstadt-Dieburg Region|Darmstadt-Dieburger Nahverkehrsorganisation
|
||||
duesseldorf|51.230794,6.769025|2018-08-29|Düsseldorf Liniennetz|Rheinbahn
|
||||
duesseldorf_nacht|51.230794,6.769025|2018-08-29|Düsseldorf Nachtlinien|Rheinbahn
|
||||
darmstadt|49.872582,8.630916|2023-12-10|Darmstadt Stadt|Darmstadt-Dieburger Nahverkehrsorganisation
|
||||
darmstadt_nacht|49.872582,8.630916|2023-12-10|Darmstadt NightLiner|Darmstadt-Dieburger Nahverkehrsorganisation
|
||||
darmstadt_region|49.872582,8.630916|2023-12-10|Darmstadt-Dieburg Region|Darmstadt-Dieburger Nahverkehrsorganisation
|
||||
duesseldorf|51.230794,6.769025|2024-01-07|Düsseldorf Liniennetz|Rheinbahn
|
||||
duesseldorf_nacht|51.230794,6.769025|2024-01-07|Düsseldorf Nachtlinien|Rheinbahn
|
||||
duisburg|51.428813,6.772554|2018-03-01|Duisburg Liniennetz|DVG/VRR
|
||||
schwerin|53.634476,11.407313|2018-07|Schwerin Liniennetz|Nahverkehr Schwerin GmbH
|
||||
magdeburg_tag|52.130783,11.627347|2018-12-03|Magdeburg Liniennetz|Magdeburger Regionalverkehrsverbund
|
||||
magdeburg_nacht|52.130783,11.627347|2018-12-03|Magdeburg Nacht-Liniennetz|Magdeburger Regionalverkehrsverbund
|
||||
magdeburg_verbund|52.130783,11.627347|2018-12|Magdeburg Verbund-Liniennetz|Magdeburger Regionalverkehrsverbund
|
||||
hagen|51.362675,7.461087|2019-12-15|Hagen Liniennetz|Hagener Straßenbahn AG
|
||||
braunschweig_gesamt|52.252187,10.539705|2019-10-03|Braunschweig Liniennetz|Braunschweiger Verkehrs-GmbH
|
||||
braunschweig_nacht|52.252187,10.539705|2019-10-03|Braunschweig Nachtnetz|Braunschweiger Verkehrs-GmbH
|
||||
magdeburg_tag|52.130783,11.627347|2021-12-24|Magdeburg Liniennetz|Magdeburger Verkehrsbetriebe GmbH & Co. KG
|
||||
magdeburg_nacht|52.130783,11.627347|2021-12-24|Magdeburg Nacht-Liniennetz|Magdeburger Verkehrsbetriebe GmbH & Co. KG
|
||||
magdeburg_verbund|52.130783,11.627347|2020-12|Magdeburg Verbund-Liniennetz|Nahverkehrsservice Sachsen-Anhalt GmbH
|
||||
hagen|51.362675,7.461087|2024-01-08|Hagen Liniennetz|Hagener Straßenbahn AG
|
||||
hagen_nacht|51.362675,7.461087|2024-01-08|Hagen Nachtnetz|Hagener Straßenbahn AG
|
||||
braunschweig_gesamt|52.252187,10.539705|2024-03-18|Braunschweig Liniennetz|Braunschweiger Verkehrs-GmbH
|
||||
braunschweig_nacht|52.252187,10.539705|2024-03-18|Braunschweig Nachtnetz|Braunschweiger Verkehrs-GmbH
|
||||
salzgitter|52.15116,10.332488|2017-12|Salzgitter Liniennetz|KVG Braunschweig
|
||||
wolfenbuettel|52.15898,10.532012|2018-10|Wolfenbüttel Liniennetz|KVG Braunschweig
|
||||
wolfenbuettel|52.15898,10.532012|2021-10|Wolfenbüttel Liniennetz|KVG Braunschweig
|
||||
helmstedt|52.222331,11.010690|2015-12|Helmstedt Liniennetz|KVG Braunschweig
|
||||
harz|51.888518,10.554843|2018-06|Harz Liniennetz|KVG Braunschweig
|
||||
wolfsburg|52.429484,10.788249|2018-08-09|Wolfsburg Liniennetz|WVG
|
||||
karlsruhe_liniennetz|48.993988,8.400328|2020-12-13|Karlsruhe Liniennetz|Karlsruher Verkehrsverbund||KVV
|
||||
karlsruhe_rolli|48.993988,8.400328|2020-12-18|Karlsruhe für mobilitätseingeschränkte Personen|Karlsruher Verkehrsverbund||KVV
|
||||
karlsruhe_liniennetz|48.993988,8.400328|2022-12-11|Karlsruhe Liniennetz|Karlsruher Verkehrsverbund||KVV
|
||||
karlsruhe_rolli|48.993988,8.400328|2021-12-12|Karlsruhe für mobilitätseingeschränkte Personen|Karlsruher Verkehrsverbund||KVV
|
||||
karlsruhe_regio|48.993988,8.400328|2020-12-13|Karlsruhe Regionalverkehr|Karlsruher Verkehrsverbund||KVV
|
||||
karlsruhe_bus|49.009498,8.404073|2020-12-13|Karlsruhe Busnetz|Karlsruher Verkehrsverbund||KVV
|
||||
karlsruhe_bus|49.009498,8.404073|2022-12-11|Karlsruhe Busnetz|Karlsruher Verkehrsverbund||KVV
|
||||
karlsruhe_nightliner|49.009498,8.404073|2020-11-28|Karlsruhe Nightliner|Karlsruher Verkehrsverbund||KVV
|
||||
badenbaden_busnetz|48.79014,8.19126|2021-02-18|Rastatt (Südlicher Landkreis) und Baden-Baden Busnetz|Karlsruher Verkehrsverbund||KVV
|
||||
rastatt_busnetz|48.86065,8.21525|2021-02-18|Karlsruhe (Südlicher Landkreis) und Rastatt (Nördlicher Landkreis) Busnetz|Karlsruher Verkehrsverbund||KVV
|
||||
bruchsal_busnetz|49.12428,8.59017|2021-02-18|Bruchsal (Nördlicher Landkreis) Busnetz|Karlsruher Verkehrsverbund||KVV
|
||||
freiburg_liniennetz|47.996556,7.840286|2019-11|Freiburg Liniennetz|Freiburger Verkehrs AG||VAGFR
|
||||
freiburg_nacht|47.996556,7.840286|2019-11|Freiburg Nachtbus|Freiburger Verkehrs AG||VAGFR
|
||||
freiburg_regio|47.996556,7.840286|2019-03|Freiburg Regio|RVF
|
||||
|
@ -142,9 +157,9 @@ rhein_neckar_regio|49.481844,8.459115|2019-11|Rhein-Neckar Regionalverkehr|RNV G
|
|||
|
||||
# at
|
||||
|
||||
linz|48.290893,14.291965|2018-10|Linz Verkehrslinienplan|Linz AG
|
||||
linz_nacht|48.290893,14.291965|2016-12|Linz Nachtverkehr|Linz AG
|
||||
innsbruck_liniennetz|47.26332,11.400951|2018|Innsbruck Liniennetz|Innsbrucker Verkehrsbetriebe GmbH
|
||||
linz|48.290893,14.291965|2024-01|Linz Verkehrslinienplan|Linz AG
|
||||
linz_nacht|48.290893,14.291965|2024-01|Linz Nachtverkehr|Linz AG
|
||||
innsbruck_liniennetz|47.26332,11.400951|2021|Innsbruck Liniennetz|Innsbrucker Verkehrsbetriebe GmbH
|
||||
innsbruck_tram|47.26332,11.400951|2012-12-15|Innsbruck Straßenbahn|Steve Stipsits|http://www.public-transport.at/netzplan_innsbruck_gross_aktuell.gif
|
||||
graz|47.073371,15.416154|2018-09-08|Graz Liniennetz|Verbund Linie
|
||||
graz_nightline|47.073371,15.416154|2018-09-08|Graz Nightline|Verbund Linie
|
||||
|
@ -188,7 +203,7 @@ amsterdam_centre|52.378861,4.900392||Amsterdam City Centre (geographical)|GVB
|
|||
copenhagen_city|55.672717,12.562532||Copenhagen City|DOT
|
||||
copenhagen_region|55.672717,12.562532||Copenhagen Greater Area|DOT
|
||||
copenhagen_night|55.672717,12.562532|2015-02|Copenhagen Night Bus|DOT
|
||||
aarhus_dag|56.149808,10.204283|2020-12-13|Aarhus Dag|Damian Leonhardt
|
||||
aarhus_dag|56.149808,10.204283|2022-06-26|Aarhus Dag|Damian Leonhardt
|
||||
|
||||
# se
|
||||
|
||||
|
@ -196,10 +211,6 @@ gothenburg_tram|57.708792,11.973538|2015-12-13|Göteborg Tram and Trunk Bus|väs
|
|||
gothenburg_commuter|57.708792,11.973538|2016-08-21|Göteborg Express Buses and Commuter Trains|västtrafik
|
||||
gothenburg_ferry|57.708792,11.973538|2015-12-13|Göteborg Tram and Ferry|västtrafik
|
||||
gothenburg_region|57.708792,11.973538|2016-01-03|Göteborg Region|västtågen
|
||||
jonkoping_bus|57.784691,14.163508||Jonkoping Bus||http://transportmaps.free.fr/maps/Sweden/Jonkoping/map_Bus_Lines.jpg
|
||||
jonkoping_map|57.784691,14.163508||Jonkoping Map (geographical)||http://transportmaps.free.fr/maps/Sweden/Jonkoping/map_Bus_Map.jpg
|
||||
linkoping_bus|58.416129,15.626714|2009-06-14|Linkoping Bus||http://transportmaps.free.fr/maps/Sweden/Linkoping/map_Bus.jpg
|
||||
stockholm_train|59.329875,18.057218||Stockholm Train|Storstockholms Lokaltrafik|http://transportmaps.free.fr/maps/Sweden/Stockholm/map_All_Trains.jpg
|
||||
|
||||
# no
|
||||
|
||||
|
@ -222,7 +233,7 @@ istanbul_rail|41.011939,28.984308|2015-09|Istanbul Rail Transit|Maximilian Dörr
|
|||
|
||||
# uk
|
||||
|
||||
london_tube|51.513507,-0.110264|2016-06|London Tube|TfL
|
||||
london_tube|51.513507,-0.110264|2023-05|London Tube|TfL
|
||||
london_overground|51.513507,-0.110264|2016-05|London Overground|TfL
|
||||
london_rail|51.513507,-0.110264|2016-05|London Rail & Tube Services|TfL
|
||||
london_bus|51.513507,-0.110264|2016|London Bus (geographical)|TfL
|
||||
|
@ -230,13 +241,7 @@ london_night|51.513507,-0.110264|2016|London Night Bus|TfL
|
|||
london_tram|51.37937,-0.101759|2016-01|London Trams|TfL
|
||||
manchester_tram|53.479754,-2.24272|2019|Manchester Tram network|Transport for Greater Manchester|https://images.ctfassets.net/nv7y93idf4jq/ZQ9ZsaDtyEoUMiwISqm4c/97b5a9cf4c29b171aaa1b50424a2efba/Metrolink-Map-2019.jpg
|
||||
menchester_train|53.479754,-2.24272|2018-11|Manchester Train network|Transport for Greater Manchester|https://images.ctfassets.net/nv7y93idf4jq/6cNIqEFra0ke8YMqAkq6Cq/22e8549c97ff4fb852713be3699145e1/Combined_Rail_Metrolink_network_map_v17__free_bus_.jpg
|
||||
bath_bus|51.377628,-2.357004||Bath Bus Network|FWT|http://transportmaps.free.fr/maps/United_Kingdom/Bath/map_Bus_Network.jpg
|
||||
bath_bus_city_center|51.377628,-2.357004||Bath Bus City Zone 1|FWT|http://transportmaps.free.fr/maps/United_Kingdom/Bath/map_City_Center_Bus.jpg
|
||||
leeds_bus|53.795649,-1.548003||Leeds Bus Network|FWT|http://transportmaps.free.fr/maps/United_Kingdom/Leeds/map_Bus.jpg
|
||||
newcastle_metro|54.972793,-1.604741||Newcastle Metro|Nexus
|
||||
nottingham_bus_city_center|52.947042,-1.146276||Nottingham City Centre Bus/Tram|FWT|http://transportmaps.free.fr/maps/United_Kingdom/Nottingham/map_Bus_NCTX_Inner_City_Map.jpg
|
||||
nottingham_bus_greater_area|52.947042,-1.146276||Nottingham Greater Area Bus||http://transportmaps.free.fr/maps/United_Kingdom/Nottingham/map_Greater_Nottingham_Buses.jpg
|
||||
york|53.957911,-1.093061||York Bus||http://transportmaps.free.fr/maps/United_Kingdom/York/map_Bus.jpg
|
||||
westmidlands_rail|52.477785,-1.898184||West Midlands Rail Network|
|
||||
|
||||
# it
|
||||
|
@ -248,17 +253,12 @@ napoli_region|40.852780,14.271692||Napoli Region|Unico Campania
|
|||
|
||||
# fr
|
||||
|
||||
paris_metro_ratp|48.855414,2.34488|2014-01|Paris Metro|RATP
|
||||
paris_metro_ratp|48.855414,2.34488|2022-12|Paris Metro|RATP
|
||||
paris_metro|48.855414,2.34488|2012-12|Paris Metro|Nathan Kaufmann, Creative Commons
|
||||
|
||||
# po
|
||||
|
||||
gdansk_tram|54.355338,18.644478|2008|Gdansk Tram|ZKM|http://transportmaps.free.fr/maps/Poland/Gdansk/map_Tram.jpg
|
||||
krakow_tram|50.065365,19.947124|2010-03-01|Krakow Tram|KST|http://transportmaps.free.fr/maps/Poland/Krakow/map_Tram.jpg
|
||||
poznan_tram|52.40144,16.91215||Poznan Tram|MPK|http://transportmaps.free.fr/maps/Poland/Poznan/map_Trams.jpg
|
||||
poznan_night|52.40144,16.91215||Poznan Night Buses|MPK|http://transportmaps.free.fr/maps/Poland/Poznan/map_Night_Buses.jpg
|
||||
warsaw_rail|52.230515,21.010702|2011-12-01|Warsaw Rail Transport|ztm|https://www.ztm.waw.pl/mapa/duze/tramwaje.gif
|
||||
warsaw_metro_tram|52.230515,21.010702||Warsaw Metro and Tram|zajcev|http://transportmaps.free.fr/maps/Poland/Warsaw/map_Subway_and_Tramway.jpg
|
||||
|
||||
# cz
|
||||
|
||||
|
@ -289,7 +289,7 @@ losangeles_system|34.05427,-118.246715|2016-06|Los Angeles System|metro.net
|
|||
losangeles_downtown|34.05427,-118.246715|2016-06|Los Angeles Downtown|metro.net
|
||||
losangeles_metro|34.05427,-118.246715|2016-05|Los Angeles Metro|metro.net|https://media.metro.net/riding_metro/maps/images/rail_map.gif
|
||||
losangeles_metro_metrolink|34.05427,-118.246715|2016-11|Los Angeles Metro & Rail|metro.net|https://media.metro.net/riding_metro/maps/images/metro_regionalrail_map.gif
|
||||
newyork_subway|40.738452,-73.991919|2010-12|New York Subway (geographical)|MTA
|
||||
newyork_subway|40.738452,-73.991919|2023-02|New York Subway (geographical)|MTA
|
||||
philadelphia_regional|39.957386,-75.180488|2012-06|Philadelphia Regional Train & Rail Transit|SEPTA
|
||||
chicago_downtown|41.878674,-87.640333|2016-02|Chicago Downtown|RTA Chicago
|
||||
chicago_trains|41.878674,-87.640333|2015-03|Chicago Train Connections|RTA Chicago
|
||||
|
|
|
@ -7,31 +7,35 @@ configurations {
|
|||
all*.exclude group: 'org.json', module: 'json'
|
||||
all*.exclude group: 'net.sf.kxml', module: 'kxml2'
|
||||
all*.exclude group: 'androidx.legacy', module: 'legacy-support-core-ui'
|
||||
all*.exclude group: 'androidx.lifecycle', module: 'lifecycle-runtime'
|
||||
all*.exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
|
||||
all*.exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':public-transport-enabler')
|
||||
implementation 'de.schildbach.wallet:integration-android:2.0'
|
||||
implementation 'androidx.annotation:annotation:1.2.0'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
|
||||
implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
|
||||
implementation 'androidx.core:core:1.6.0'
|
||||
implementation(project(':public-transport-enabler')) {
|
||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||
}
|
||||
implementation 'androidx.annotation:annotation:1.8.2'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.3.2'
|
||||
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
|
||||
implementation 'androidx.drawerlayout:drawerlayout:1.2.0'
|
||||
implementation 'androidx.core:core:1.13.1'
|
||||
implementation 'androidx.activity:activity:1.9.3'
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.12.13'
|
||||
//noinspection GradleDependency
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:3.12.13'
|
||||
implementation 'com.google.guava:guava:31.0.1-android'
|
||||
implementation 'org.osmdroid:osmdroid-android:6.1.11'
|
||||
implementation 'org.slf4j:slf4j-api:1.7.32'
|
||||
implementation 'com.github.tony19:logback-android:2.0.0'
|
||||
implementation 'com.google.guava:guava:33.4.0-android'
|
||||
implementation 'org.osmdroid:osmdroid-android:6.1.20'
|
||||
//noinspection GradleDependency
|
||||
implementation 'org.slf4j:slf4j-api:2.0.9'
|
||||
implementation 'com.github.tony19:logback-android:3.0.0'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 'android-30'
|
||||
buildToolsVersion '30.0.3'
|
||||
compileSdkVersion 'android-34'
|
||||
buildToolsVersion '35.0.0'
|
||||
|
||||
defaultConfig {
|
||||
generatedDensities = ['hdpi', 'xhdpi']
|
||||
|
@ -49,18 +53,6 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
flavorDimensions 'flavor'
|
||||
productFlavors {
|
||||
aosp {
|
||||
dimension 'flavor'
|
||||
versionNameSuffix '-aosp'
|
||||
}
|
||||
google {
|
||||
dimension 'flavor'
|
||||
versionNameSuffix '-google'
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
manifest.srcFile 'AndroidManifest.xml'
|
||||
|
@ -71,12 +63,6 @@ android {
|
|||
test {
|
||||
java.srcDirs = ['test']
|
||||
}
|
||||
aosp {
|
||||
java.srcDirs = ['src-aosp']
|
||||
}
|
||||
google {
|
||||
java.srcDirs = ['src-google']
|
||||
}
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
|
@ -86,15 +72,16 @@ android {
|
|||
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
disable 'MissingTranslation'
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/*.version'
|
||||
exclude 'META-INF/proguard/**'
|
||||
exclude 'META-INF/services/**'
|
||||
exclude 'META-INF/*.kotlin_module'
|
||||
exclude 'META-INF/**/coroutines.pro'
|
||||
exclude 'DebugProbesKt.bin'
|
||||
exclude 'kotlin/**'
|
||||
exclude 'okhttp3/internal/publicsuffix/publicsuffixes.gz'
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
-dontskipnonpubliclibraryclasses
|
||||
-android
|
||||
-dontoptimize
|
||||
-dontpreverify
|
||||
-dontobfuscate
|
||||
|
@ -46,9 +46,18 @@
|
|||
}
|
||||
|
||||
# androidx
|
||||
-dontwarn androidx.core.**
|
||||
-dontwarn kotlinx.coroutines.**
|
||||
-dontwarn module-info
|
||||
-dontnote androidx.core.**
|
||||
-dontnote androidx.versionedparcelable.VersionedParcel
|
||||
-dontnote kotlin.**
|
||||
-dontnote kotlinx.**
|
||||
-dontwarn androidx.lifecycle.SavedStateHandle
|
||||
-dontwarn androidx.activity.Api34Impl
|
||||
-dontwarn androidx.activity.BackEventCompat
|
||||
-dontnote androidx.activity.ImmLeaksCleaner$Companion$**
|
||||
-dontwarn androidx.core.view.accessibility.AccessibilityNodeInfoCompat$AccessibilityActionCompat
|
||||
-dontwarn androidx.**$Api34Impl,androidx.**$Api34Impl$**
|
||||
|
||||
# OkHttp
|
||||
-dontwarn okio.DeflaterSink
|
||||
|
@ -63,22 +72,20 @@
|
|||
|
||||
# Guava
|
||||
-dontwarn sun.misc.Unsafe
|
||||
-dontwarn java.lang.ClassValue
|
||||
-dontwarn com.google.errorprone.annotations.**
|
||||
-dontwarn afu.org.checkerframework.checker.**,org.checkerframework.checker.**
|
||||
-dontwarn javax.lang.model.element.Modifier
|
||||
-dontwarn com.google.common.reflect.Invokable,com.google.common.reflect.Invokable$**
|
||||
-dontwarn java.lang.reflect.AnnotatedType
|
||||
-dontnote com.google.common.reflect.**
|
||||
-dontnote com.google.appengine.**
|
||||
-dontnote com.google.apphosting.**
|
||||
-dontnote com.google.common.cache.Striped64,com.google.common.cache.Striped64$Cell
|
||||
-dontnote com.google.common.hash.Striped64,com.google.common.hash.Striped64$Cell
|
||||
-dontnote com.google.common.util.concurrent.AbstractFuture$UnsafeAtomicHelper
|
||||
-dontnote com.google.common.io.TempFileCreator,com.google.common.io.TempFileCreator$**
|
||||
-dontnote dalvik.system.CloseGuard
|
||||
|
||||
# slf4j
|
||||
-dontwarn org.slf4j.MDC
|
||||
-dontwarn org.slf4j.MarkerFactory
|
||||
|
||||
# logback-android
|
||||
# SLF4J, logback-android
|
||||
-keep class org.slf4j.impl.LoggerServiceProvider
|
||||
-dontwarn javax.mail.**
|
||||
-dontnote ch.qos.logback.core.android.AndroidContextUtil
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z" />
|
||||
</vector>
|
|
@ -1,25 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="48dp"
|
||||
android:viewportHeight="127.8"
|
||||
android:viewportWidth="127.8"
|
||||
android:width="48dp">
|
||||
|
||||
<path
|
||||
android:fillColor="#DD0B2F"
|
||||
android:pathData="M32.7,46.2l11.5,0l-35.2,35.2l-9,0l0,-35.2l8.7,0l0,23.9z" />
|
||||
<path
|
||||
android:fillColor="#008244"
|
||||
android:pathData="M48.1,57.5l-23.9,23.9l-11.5,0l35.1,-35.2l9,0l0,24.1l24,-24.1l8.8,0l0,35.2l-8.8,0l0,-23.6l-23.7,23.6l-9,0z" />
|
||||
<path
|
||||
android:fillColor="#DD0B2F"
|
||||
android:pathData="m56.8,42.5v-15.7h-15.7v6.8c0,0 1.3,0 2.2,0 0.9,-0.1 1.6,-0.2 1.6,-0.2l-9.1,9.2L46,42.6l4.2,-4.2c0,0 -0.3,1.2 -0.3,2 -0.1,0.8 -0.1,2.2 -0.1,2.2h7z" />
|
||||
<path
|
||||
android:fillColor="#008244"
|
||||
android:pathData="m126.5,46.2v8.6L103,54.8c-0.3,0 -1.1,0.1 -1.5,0.6 -0.4,0.5 -0.6,0.9 -0.6,1.5v1.1c0,0.1 0.1,0.6 0.4,1 0.3,0.4 0.7,0.7 1.3,0.7h16.8c1.1,0 4.1,1 5.8,2.9 1.9,2 2.6,4.4 2.6,6.6 0,1.4 0,3.6 0,3.6 0,1 -0.8,3.8 -2.1,5.1 -2.6,2.6 -5.9,3.4 -7.9,3.4h-25.6v-8.6h25.6c0.5,0 0.7,-0.1 1.1,-0.4 0.3,-0.3 0.5,-0.5 0.5,-0.9v-2.2c0,-0.4 -0.2,-0.5 -0.4,-0.8 -0.4,-0.4 -0.9,-0.6 -1.2,-0.6L101,67.8c-0.4,0 -3,0.4 -6.2,-3 -1.8,-1.9 -2.2,-4.8 -2.2,-5.1v-3.5c0,-2.6 0.8,-4.7 2.2,-6.4 2.2,-2.6 5.1,-3.6 7.8,-3.6z" />
|
||||
<path
|
||||
android:fillColor="#008244"
|
||||
android:pathData="m0,85.3v15.7h15.7v-6.8c0,0 -1.3,0 -2.2,0 -0.9,0.1 -1.6,0.2 -1.6,0.2l9.1,-9.2h-10.3l-4.2,4.2c0,0 0.3,-1.2 0.3,-2 0.1,-0.8 0.1,-2.2 0.1,-2.2L0,85.2Z" />
|
||||
|
||||
</vector>
|
|
@ -1,65 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:viewportWidth="377.9467"
|
||||
android:viewportHeight="377.9467"
|
||||
android:width="48dp"
|
||||
android:height="48dp">
|
||||
<group
|
||||
android:scaleX="1.333333"
|
||||
android:scaleY="-1.333333"
|
||||
android:translateY="377.9467">
|
||||
<group
|
||||
android:scaleX="0.1"
|
||||
android:scaleY="0.1">
|
||||
<path
|
||||
android:pathData="M2551.18 0.0117188H283.469C127.559 0.0117188 0 127.57 0 283.469V2551.18c0 155.91 127.559 283.47 283.469 283.47H2551.18c155.91 0 283.47 -127.56 283.47 -283.47V283.469C2834.65 127.57 2707.09 0.0117188 2551.18 0.0117188"
|
||||
android:fillColor="#FFFFFF" />
|
||||
<path
|
||||
android:pathData="M2233.03 1543.85h436.03v123.91h-436.03v-123.91 0 0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#127BCA" />
|
||||
<path
|
||||
android:pathData="M2234.08 1348.53h434.46v123.9h-434.46v-123.9 0 0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#127BCA" />
|
||||
<path
|
||||
android:pathData="M2669.06 1153.75v123.9h-436.03v-123.9h436.03v0"
|
||||
android:fillColor="#127BCA" />
|
||||
<path
|
||||
android:pathData="M2233.03 1667.75v-123.9h218.54v0c-43.81 74.66 -123.08 123.9 -213.85 123.9 -1.56 0 -3.12 0 -4.69 0v0 0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#231F20" />
|
||||
<path
|
||||
android:pathData="M2234.08 1472.43v-123.9h250.88v0c7.3 21.09 9.9 44.91 9.9 62.22 0 16.77 -2.09 46.5 -10.43 61.65l-250.35 0.03v0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#231F20" />
|
||||
<path
|
||||
android:pathData="M2236.69 1153.75h2.08c89.72 0.54 170.56 49.77 214.89 123.9h-220.63v-123.9c1.05 0 2.61 0 3.66 0v0 0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#231F20" />
|
||||
<path
|
||||
android:pathData="M2016.59 1543.8c43.82 74.67 126.24 123.96 216.48 123.96v-123.91l-216.48 -0.05v0 0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#2EA53A" />
|
||||
<path
|
||||
android:pathData="M1975.39 1410.75c0 16.77 5.22 46 8.88 61.68v0h249.85v-123.92l-249.85 0.02v0c-4.18 16.22 -8.88 44.91 -8.88 62.22v0 0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#2EA53A" />
|
||||
<path
|
||||
android:pathData="M2233.07 1153.75c-90.24 0 -172.66 49.77 -216.48 123.9v0l216.48 0.03v-123.93 0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#2EA53A" />
|
||||
<path
|
||||
android:pathData="M740.262 1667.75L956.02 1154.84h105.93l216.14 512.91h-150.05l-92.42 -262.46c-13.89 -33.17 -20.3 -66.07 -26.47 -92.3 -13.142 52.98 -14.923 63.01 -24.904 90.19l-94.168 264.57H740.262v0"
|
||||
android:fillColor="#231F20" />
|
||||
<path
|
||||
android:pathData="M1560.7 1560.42c75.09 0 134.57 -70.38 134.57 -151.51 0 -81.13 -59.48 -149.64 -134.57 -149.64 -75.83 0 -134.73 69.84 -134.73 150.97 0 81.13 58.9 150.18 134.73 150.18zm0 118.94c-151.67 0 -274.05 -120.12 -274.05 -269.12 0 -148.99 122.38 -269.12 274.05 -269.12 150.92 0 273.31 120.13 273.31 269.12 0 149 -122.39 269.12 -273.31 269.12v0"
|
||||
android:fillType="evenOdd"
|
||||
android:fillColor="#231F20" />
|
||||
<path
|
||||
android:pathData="M165.586 1667.75l215.769 -512.91h105.926l216.137 512.91H553.367l-92.414 -262.46c-13.894 -33.17 -20.305 -66.07 -26.48 -92.3 -13.141 52.98 -14.922 63.01 -24.899 90.19L315.41 1667.75H165.586v0"
|
||||
android:fillColor="#231F20" />
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
Binary file not shown.
Before Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB |
|
@ -4,6 +4,7 @@
|
|||
android:id="@+id/plans_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/bg_plan"
|
||||
android:inAnimation="@android:anim/fade_in"
|
||||
android:outAnimation="@android:anim/fade_out">
|
||||
|
||||
|
@ -24,7 +25,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:text="@string/plan_progress_loading"
|
||||
android:textColor="@color/fg_significant_on_dark"
|
||||
android:textColor="@color/fg_significant_on_light"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
|
||||
|
|
|
@ -3,24 +3,8 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/station_map_context_google_maps"
|
||||
android:id="@+id/station_map_context_maps"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/map_dialog_google_maps" />
|
||||
<item
|
||||
android:id="@+id/station_map_context_amazon_maps"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/map_dialog_amazon_maps" />
|
||||
<item
|
||||
android:id="@+id/station_map_context_openstreetmap"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/map_dialog_openstreetmap" />
|
||||
<item
|
||||
android:id="@+id/station_map_context_google_street_view"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/map_dialog_google_street_view" />
|
||||
<item
|
||||
android:id="@+id/station_map_context_google_navigation"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/map_dialog_google_navigation" />
|
||||
android:title="@string/map_dialog_maps" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
<string name="directions_location_context_current_location">Mein aktueller Standort</string>
|
||||
<string name="directions_location_context_contact">Adresse aus Kontakt</string>
|
||||
<string name="directions_location_context_favorite_station">Haltestellen-Favorit</string>
|
||||
<string name="directions_location_choose_error_permission">Berechtigungs-Problem:\n%1$s</string>
|
||||
<string name="directions_products_prompt">Verkehrsmittel auswählen</string>
|
||||
|
||||
<string-array name="directions_products">
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<string name="network_mvv_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_invg_label">Ingolstadt</string>
|
||||
<string name="network_invg_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_avv_label">Augsburg</string>
|
||||
<string name="network_avv_comment">nur Tram und Bus</string>
|
||||
<string name="network_avv_augsburg_label">Augsburg</string>
|
||||
<string name="network_avv_augsburg_comment">nur Tram und Bus</string>
|
||||
<string name="network_vgn_label">Verkehrsverbund Großraum Nürnberg</string>
|
||||
<string name="network_vgn_comment">Nürnberg, Fürth & Erlangen, Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vvm_label">Mittelschwaben (Krumbach, Günzburg, …)</string>
|
||||
|
@ -39,10 +39,8 @@
|
|||
<string name="network_nasa_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vmt_label">Erfurt, Jena & Mittelthüringen</string>
|
||||
<string name="network_vmt_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vvo_label">Verkehrsverbund Oberelbe</string>
|
||||
<string name="network_vvo_comment">Dresden, Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vms_label">Verkehrsverbund Mittelsachsen</string>
|
||||
<string name="network_vms_comment">Chemnitz & Mittelsachsen, Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vvo_label">Sachsen</string>
|
||||
<string name="network_vvo_comment">Dresden & Chemnitz, Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vrr_label">Verkehrsverbund Rhein-Ruhr</string>
|
||||
<string name="network_vrr_comment">Nordrhein-Westfalen, Düsseldorf & Dortmund, Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vrs_label">Köln & Bonn</string>
|
||||
|
@ -83,20 +81,10 @@
|
|||
<string name="network_stv_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vmobil_label">Bregenz & Vorarlberg</string>
|
||||
<string name="network_vmobil_comment">Nicht verfügbar, weil der VVV ausdrücklich darum gebeten hat, nicht in Öffi enthalten zu sein. Du kannst stattdessen die ÖBB verwenden, das funktioniert für Vorarlberg auch gut.</string>
|
||||
<string name="network_czech_republic_label">Prag</string>
|
||||
<string name="network_czech_republic_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_vbl_label">Luzern</string>
|
||||
<string name="network_vbl_comment">nur Tram und Bus</string>
|
||||
<string name="network_zvv_label">Zürich</string>
|
||||
<string name="network_zvv_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_it_label">Italien</string>
|
||||
<string name="network_it_comment">Fern-, Regional und Lokalverkehr (z.B. Mailand, Rom, Neapel)</string>
|
||||
<string name="network_paris_label">Paris</string>
|
||||
<string name="network_paris_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_spain_label">Spanien</string>
|
||||
<string name="network_spain_comment">Lokal- und Regionalverkehr (z.B. Barcelona)</string>
|
||||
<string name="network_sncb_label">Belgien</string>
|
||||
<string name="network_sncb_comment">Fern-, Regional und Lokalverkehr (z.B. Antwerpen, Gent, Charleroi, Brüssel)</string>
|
||||
<string name="network_lu_label">Luxemburg</string>
|
||||
<string name="network_lu_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_ns_label">Niederlande</string>
|
||||
|
@ -105,14 +93,10 @@
|
|||
<string name="network_dsb_comment">Fern-, Regional und Lokalverkehr (z.B. Kopenhagen)</string>
|
||||
<string name="network_se_label">Schweden</string>
|
||||
<string name="network_se_comment">Fern-, Regional und Lokalverkehr (z.B. Stockholm)</string>
|
||||
<string name="network_finland_label">Finnland</string>
|
||||
<string name="network_finland_comment">Fern-, Regional und Lokalverkehr (z.B. Helsinki)</string>
|
||||
<string name="network_tlem_label">England, Schottland & Wales.</string>
|
||||
<string name="network_tlem_comment">Lokal- und Regionalverkehr (z.B. London, Birmingham)</string>
|
||||
<string name="network_mersey_label">Liverpool</string>
|
||||
<string name="network_mersey_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_tfi_label">Irland & Nordirland</string>
|
||||
<string name="network_tfi_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_pl_label">Polen</string>
|
||||
<string name="network_pl_comment">Fern-, Regional und Lokalverkehr (z.B. Warschau)</string>
|
||||
<string name="network_dub_label">Dubai</string>
|
||||
|
@ -125,8 +109,6 @@
|
|||
<string name="network_cmta_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_sydney_label">Sydney</string>
|
||||
<string name="network_sydney_comment">Lokal- und Regionalverkehr</string>
|
||||
<string name="network_nicaragua_label">Nicaragua</string>
|
||||
<string name="network_nicaragua_comment">nationale und städtische Buslinien</string>
|
||||
<string name="network_met_label">Melbourne</string>
|
||||
<string name="network_met_comment">Nicht mehr verfügbar, da der PTV keine EFA-API mehr anbietet.</string>
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="map_dialog_google_maps">Google Maps</string>
|
||||
<string name="map_dialog_amazon_maps">Amazon Maps</string>
|
||||
<string name="map_dialog_openstreetmap">OpenStreetMap</string>
|
||||
<string name="map_dialog_google_street_view">Street View</string>
|
||||
<string name="map_dialog_google_navigation">Navigation für Fußgänger</string>
|
||||
<string name="map_dialog_maps">externe Karte</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -134,7 +134,6 @@
|
|||
<string name="stations_search_list_empty">Keine Haltestellen gefunden</string>
|
||||
|
||||
<!-- station details -->
|
||||
<string name="stations_station_details_intentfilter_title">Abfahrtszeiten an dieser Haltestelle</string>
|
||||
<string name="stations_station_details_action_favorite_title">Favorit</string>
|
||||
<string name="stations_station_details_progress">Lade Abfahrtszeiten…</string>
|
||||
<string name="stations_station_details_list_empty">Keine Abfahrten</string>
|
||||
|
@ -330,7 +329,6 @@
|
|||
<string name="alert_crash_report_positive">Senden</string>
|
||||
<string name="alert_crash_report_download">Herunterladen</string>
|
||||
<string name="alert_crash_report_negative">Schließen</string>
|
||||
<string name="notification_channel_appwidget_name">App-Widget-Aktivität</string>
|
||||
|
||||
<!-- products -->
|
||||
<string name="product_i">Fernverkehr</string>
|
||||
|
@ -356,6 +354,7 @@
|
|||
<string name="time_hours">%1$dh %2$02d min</string>
|
||||
|
||||
<!-- position -->
|
||||
<string name="position_platform">Gleis %s</string>
|
||||
<string name="position_platform_train">Gleis %s</string>
|
||||
<string name="position_platform">Steig %s</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- background -->
|
||||
<color name="bg_status_bar">@android:color/transparent</color>
|
||||
<color name="bg_navigation_bar">@android:color/transparent</color>
|
||||
<color name="bg_navigation_bar_fullscreen">@android:color/transparent</color>
|
||||
|
||||
</resources>
|
|
@ -23,7 +23,6 @@
|
|||
<color name="bg_delayed">#444444</color>
|
||||
<color name="bg_current_time">#ffff00</color>
|
||||
<color name="bg_position">#bbbbbb</color>
|
||||
<color name="bg_status_bar">#44000000</color>
|
||||
|
||||
<item name="alpha_bright_white" format="float" type="dimen">0.8</item>
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
<style name="My.Theme" parent="@android:style/Theme.Material.NoActionBar">
|
||||
<item name="android:windowBackground">@color/bg_level0</item>
|
||||
<item name="android:statusBarColor">@color/bg_status_bar</item>
|
||||
<item name="android:navigationBarColor">@color/bg_navigation_bar</item>
|
||||
<item name="android:textViewStyle">@style/My.Widget.TextView</item>
|
||||
<item name="android:autoCompleteTextViewStyle">@style/My.Widget.AutoCompleteTextView</item>
|
||||
<item name="android:dropDownListViewStyle">@style/My.Widget.ListView.DropDown</item>
|
||||
|
@ -17,8 +15,6 @@
|
|||
</style>
|
||||
|
||||
<style name="My.Theme.Preference" parent="@android:style/Theme.Material">
|
||||
<item name="android:statusBarColor">@color/bg_action_bar</item>
|
||||
<item name="android:navigationBarColor">@color/bg_level0</item>
|
||||
<item name="android:actionBarStyle">@style/My.Widget.ActionBar</item>
|
||||
</style>
|
||||
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
|
||||
<style name="My.Theme.DarkDefault" parent="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@color/bg_level0_darkdefault</item>
|
||||
<item name="android:statusBarColor">@color/bg_status_bar</item>
|
||||
<item name="android:navigationBarColor">@color/bg_navigation_bar</item>
|
||||
<item name="android:textViewStyle">@style/My.Widget.TextView.DarkDefault</item>
|
||||
<item name="android:imageButtonStyle">@style/My.Widget.ImageButton</item>
|
||||
</style>
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- background -->
|
||||
<color name="bg_status_bar">@android:color/transparent</color>
|
||||
<color name="bg_navigation_bar">@android:color/transparent</color>
|
||||
<color name="bg_navigation_bar_fullscreen">@android:color/transparent</color>
|
||||
|
||||
</resources>
|
|
@ -37,9 +37,7 @@
|
|||
<color name="bg_position">#757575</color>
|
||||
<color name="bg_position_darkdefault">#bbbbbb</color>
|
||||
<color name="bg_highlighted_darkdefault">#ff4444</color>
|
||||
<color name="bg_status_bar">#44000000</color>
|
||||
<color name="bg_navigation_bar">@android:color/black</color>
|
||||
<color name="bg_navigation_bar_fullscreen">#44000000</color>
|
||||
<color name="bg_plan">#ffd8d8d8</color>
|
||||
|
||||
<item name="alpha_bright_white" format="float" type="dimen">1</item>
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
<string name="directions_location_context_current_location">My current location</string>
|
||||
<string name="directions_location_context_contact">Contact address</string>
|
||||
<string name="directions_location_context_favorite_station">Favorite station</string>
|
||||
<string name="directions_location_choose_error_permission">Permission problem:\n%1$s</string>
|
||||
<string name="directions_products_prompt">Pick means of transport</string>
|
||||
|
||||
<string-array name="directions_products">
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
<string name="network_mvv_comment">local and regional</string>
|
||||
<string name="network_invg_label">Ingolstadt</string>
|
||||
<string name="network_invg_comment">local and regional</string>
|
||||
<string name="network_avv_label">Augsburg</string>
|
||||
<string name="network_avv_comment">tram and bus only</string>
|
||||
<string name="network_avv_augsburg_label">Augsburg</string>
|
||||
<string name="network_avv_augsburg_comment">tram and bus only</string>
|
||||
<string name="network_vgn_label">Verkehrsverbund Großraum Nürnberg</string>
|
||||
<string name="network_vgn_comment">Nuremberg, Fürth & Erlangen, local and regional</string>
|
||||
<string name="network_vvm_label">Mittelschwaben (Krumbach, Günzburg, …)</string>
|
||||
|
@ -38,10 +38,8 @@
|
|||
<string name="network_nasa_comment">local and regional</string>
|
||||
<string name="network_vmt_label">Erfurt, Jena & Central Thuringia</string>
|
||||
<string name="network_vmt_comment">local and regional</string>
|
||||
<string name="network_vvo_label">Verkehrsverbund Oberelbe</string>
|
||||
<string name="network_vvo_comment">Dresden, local and regional</string>
|
||||
<string name="network_vms_label">Verkehrsverbund Mittelsachsen</string>
|
||||
<string name="network_vms_comment">Chemnitz & Mittelsachsen, local and regional</string>
|
||||
<string name="network_vvo_label">Saxony</string>
|
||||
<string name="network_vvo_comment">Dresden & Chemnitz, local and regional</string>
|
||||
<string name="network_vrr_label">Verkehrsverbund Rhein-Ruhr</string>
|
||||
<string name="network_vrr_comment">North Rhine-Westphalia, Düsseldorf & Dortmund, local and regional</string>
|
||||
<string name="network_vrs_label">Cologne & Bonn</string>
|
||||
|
@ -83,20 +81,10 @@
|
|||
<string name="network_stv_comment">local and regional</string>
|
||||
<string name="network_vmobil_label">Bregenz & Vorarlberg</string>
|
||||
<string name="network_vmobil_comment">Not available, because the VVV explicitly desires not to be included in Offi. You can use the ÖBB instead, it works well for Vorarlberg too.</string>
|
||||
<string name="network_czech_republic_label">Prague</string>
|
||||
<string name="network_czech_republic_comment">local and regional</string>
|
||||
<string name="network_vbl_label">Lucerne</string>
|
||||
<string name="network_vbl_comment">tram and bus only</string>
|
||||
<string name="network_zvv_label">Zurich</string>
|
||||
<string name="network_zvv_comment">local and regional</string>
|
||||
<string name="network_it_label">Italy</string>
|
||||
<string name="network_it_comment">long-distance, regional and local (e.g. Milan, Rome, Naples)</string>
|
||||
<string name="network_paris_label">Paris</string>
|
||||
<string name="network_paris_comment">local and regional</string>
|
||||
<string name="network_spain_label">Spain</string>
|
||||
<string name="network_spain_comment">local and regional (e.g. Barcelona)</string>
|
||||
<string name="network_sncb_label">Belgium</string>
|
||||
<string name="network_sncb_comment">long-distance, regional and local (e.g. Antwerp, Ghent, Charleroi, Brussels)</string>
|
||||
<string name="network_lu_label">Luxembourg</string>
|
||||
<string name="network_lu_comment">local and regional</string>
|
||||
<string name="network_ns_label">Netherlands</string>
|
||||
|
@ -105,14 +93,10 @@
|
|||
<string name="network_dsb_comment">long-distance, regional and local (e.g. Copenhagen)</string>
|
||||
<string name="network_se_label">Sweden</string>
|
||||
<string name="network_se_comment">long-distance, regional and local (e.g. Stockholm)</string>
|
||||
<string name="network_finland_label">Finland</string>
|
||||
<string name="network_finland_comment">long-distance, regional and local (e.g. Helsinki)</string>
|
||||
<string name="network_tlem_label">England, Scotland & Wales</string>
|
||||
<string name="network_tlem_comment">local and regional (e.g. London, Birmingham)</string>
|
||||
<string name="network_mersey_label">Liverpool</string>
|
||||
<string name="network_mersey_comment">local and regional</string>
|
||||
<string name="network_tfi_label">Ireland & Northern Ireland</string>
|
||||
<string name="network_tfi_comment">local and regional</string>
|
||||
<string name="network_pl_label">Poland</string>
|
||||
<string name="network_pl_comment">long-distance, regional and local (e.g. Warsaw)</string>
|
||||
<string name="network_dub_label">Dubai</string>
|
||||
|
@ -125,8 +109,6 @@
|
|||
<string name="network_cmta_comment">local and regional</string>
|
||||
<string name="network_sydney_label">Sydney</string>
|
||||
<string name="network_sydney_comment">local and regional</string>
|
||||
<string name="network_nicaragua_label">Nicaragua</string>
|
||||
<string name="network_nicaragua_comment">national and urban buses</string>
|
||||
<string name="network_met_label">Melbourne</string>
|
||||
<string name="network_met_comment">Not available, because the PTV does not offer an EFA API any more.</string>
|
||||
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="map_dialog_google_maps">Google Maps</string>
|
||||
<string name="map_dialog_amazon_maps">Amazon Maps</string>
|
||||
<string name="map_dialog_openstreetmap">OpenStreetMap</string>
|
||||
<string name="map_dialog_google_street_view">Street View</string>
|
||||
<string name="map_dialog_google_navigation">Walking Directions</string>
|
||||
<string name="map_dialog_maps">External map</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<!-- preferences about -->
|
||||
<string name="about_title">About Offi</string>
|
||||
<string name="about_copyright_title">Copyright</string>
|
||||
<string name="about_copyright_summary">© 2010-2021, the Öffi developers</string>
|
||||
<string name="about_copyright_summary">© 2010-2025, the Öffi developers</string>
|
||||
<string name="about_license_title">License</string>
|
||||
<string name="about_privacy_policy_title">Privacy Policy</string>
|
||||
<string name="about_privacy_policy_url">https://oeffi.schildbach.de/privacy_policy.txt</string>
|
||||
|
@ -60,6 +60,7 @@
|
|||
<string name="about_donate_title">Donations</string>
|
||||
<string name="about_donate_bitcoin_title">Donate Bitcoins</string>
|
||||
<string name="about_donate_bitcoin_summary">Bitcoin is an Internet currency.</string>
|
||||
<string name="about_donate_bitcoin_uri">bitcoin:bc1q8ruc8hanp7hrzfs48dvtuzz4ukmpe7cgsvvzrt</string>
|
||||
<string name="about_donate_euro_title">Donate Euros</string>
|
||||
<string name="about_donate_euro_summary">https://oeffi.schildbach.de/donate.html</string>
|
||||
|
||||
|
@ -135,7 +136,6 @@
|
|||
<string name="stations_search_list_empty">No stations found</string>
|
||||
|
||||
<!-- station details -->
|
||||
<string name="stations_station_details_intentfilter_title">Departure times of this station</string>
|
||||
<string name="stations_station_details_action_favorite_title">Favorite</string>
|
||||
<string name="stations_station_details_progress">Loading departures…</string>
|
||||
<string name="stations_station_details_list_empty">No departures</string>
|
||||
|
@ -331,7 +331,6 @@
|
|||
<string name="alert_crash_report_positive">Send</string>
|
||||
<string name="alert_crash_report_download">Download</string>
|
||||
<string name="alert_crash_report_negative">Dismiss</string>
|
||||
<string name="notification_channel_appwidget_name">App-widget activity</string>
|
||||
|
||||
<!-- products -->
|
||||
<string name="product_i">Highspeed</string>
|
||||
|
@ -357,6 +356,7 @@
|
|||
<string name="time_hours">%1$dh %2$02d min</string>
|
||||
|
||||
<!-- position -->
|
||||
<string name="position_platform_train">platform %s</string>
|
||||
<string name="position_platform">platform %s</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
|
||||
<style name="My.Theme" parent="@android:style/Theme.Material.Light.NoActionBar">
|
||||
<item name="android:windowBackground">@color/bg_level0</item>
|
||||
<item name="android:statusBarColor">@color/bg_status_bar</item>
|
||||
<item name="android:navigationBarColor">@color/bg_navigation_bar</item>
|
||||
<item name="android:textViewStyle">@style/My.Widget.TextView</item>
|
||||
<item name="android:autoCompleteTextViewStyle">@style/My.Widget.AutoCompleteTextView</item>
|
||||
<item name="android:dropDownListViewStyle">@style/My.Widget.ListView.DropDown</item>
|
||||
|
@ -18,8 +16,6 @@
|
|||
|
||||
<style name="My.Theme.DarkDefault" parent="@android:style/Theme.Material.NoActionBar">
|
||||
<item name="android:windowBackground">@color/bg_level0_darkdefault</item>
|
||||
<item name="android:statusBarColor">@color/bg_status_bar</item>
|
||||
<item name="android:navigationBarColor">@color/bg_navigation_bar</item>
|
||||
<item name="android:textViewStyle">@style/My.Widget.TextView.DarkDefault</item>
|
||||
<item name="android:imageButtonStyle">@style/My.Widget.ImageButton</item>
|
||||
</style>
|
||||
|
@ -27,13 +23,10 @@
|
|||
<style name="My.Theme.Fullscreen" parent="@android:style/Theme.Material.Light.NoActionBar.Fullscreen">
|
||||
<item name="android:windowBackground">@android:color/black</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="27">shortEdges</item>
|
||||
<item name="android:navigationBarColor">@color/bg_navigation_bar_fullscreen</item>
|
||||
<item name="android:textViewStyle">@style/My.Widget.TextView</item>
|
||||
</style>
|
||||
|
||||
<style name="My.Theme.Preference" parent="@android:style/Theme.Material.Light.DarkActionBar">
|
||||
<item name="android:statusBarColor">@color/bg_action_bar</item>
|
||||
<item name="android:navigationBarColor">@color/bg_level0</item>
|
||||
<item name="android:actionBarStyle">@style/My.Widget.ActionBar</item>
|
||||
</style>
|
||||
|
||||
|
|
5
oeffi/res/xml/locale_config.xml
Normal file
5
oeffi/res/xml/locale_config.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<locale android:name="en" />
|
||||
<locale android:name="de" />
|
||||
</locale-config>
|
|
@ -6,5 +6,4 @@
|
|||
android:minResizeHeight="55dp"
|
||||
android:minWidth="294dp"
|
||||
android:previewImage="@drawable/nearest_favorite_station_widget_preview"
|
||||
android:resizeMode="horizontal|vertical"
|
||||
android:updatePeriodMillis="1800000" />
|
||||
android:resizeMode="horizontal|vertical" />
|
||||
|
|
|
@ -10,13 +10,11 @@
|
|||
|
||||
<!-- This is the hall of shame: public transport authorities which still do not support HTTPS. -->
|
||||
<domain-config cleartextTrafficPermitted="true">
|
||||
<domain includeSubdomains="false">www.belgianrail.be</domain><!-- SNCB/NMBS -->
|
||||
<domain includeSubdomains="false">android.vrsinfo.de</domain><!-- VRS -->
|
||||
<domain includeSubdomains="false">wojhati.rta.ae</domain><!-- RTA Dubai -->
|
||||
<domain includeSubdomains="false">appefa10.verbundlinie.at</domain><!-- STV -->
|
||||
<domain includeSubdomains="false">railteam.hafas.eu</domain><!-- Railteam -->
|
||||
<domain includeSubdomains="false">mobil.vbl.ch</domain><!-- VBL -->
|
||||
<domain includeSubdomains="false">efa.vvo-online.de</domain><!-- VVO -->
|
||||
<domain includeSubdomains="false">mobil.rozklad-pkp.pl</domain><!-- PKP -->
|
||||
</domain-config>
|
||||
|
||||
|
|
|
@ -5,7 +5,11 @@
|
|||
<Preference
|
||||
android:key="about_donate_bitcoin"
|
||||
android:summary="@string/about_donate_bitcoin_summary"
|
||||
android:title="@string/about_donate_bitcoin_title" />
|
||||
android:title="@string/about_donate_bitcoin_title">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="@string/about_donate_bitcoin_uri" />
|
||||
</Preference>
|
||||
<Preference
|
||||
android:key="about_donate_euro"
|
||||
android:summary="@string/about_donate_euro_summary"
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.schildbach.oeffi;
|
||||
|
||||
public class Variants {
|
||||
public static final boolean ENABLE_DONATE = true;
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.schildbach.oeffi;
|
||||
|
||||
public class Variants {
|
||||
public static final boolean ENABLE_DONATE = false;
|
||||
}
|
|
@ -17,13 +17,9 @@
|
|||
|
||||
package de.schildbach.oeffi;
|
||||
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.LoggerContext;
|
||||
|
@ -35,7 +31,6 @@ import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
|
|||
import com.google.common.base.Stopwatch;
|
||||
import de.schildbach.oeffi.directions.QueryHistoryProvider;
|
||||
import de.schildbach.oeffi.stations.FavoriteStationsProvider;
|
||||
import de.schildbach.oeffi.stations.NearestFavoriteStationWidgetService;
|
||||
import de.schildbach.oeffi.util.ErrorReporter;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import okhttp3.OkHttpClient;
|
||||
|
@ -91,38 +86,76 @@ public class Application extends android.app.Application {
|
|||
|
||||
final Stopwatch watch = Stopwatch.createStarted();
|
||||
|
||||
// 2018-07-06: migrate IVB to use OEBB
|
||||
final String IVB = "IVB";
|
||||
migrateSelectedNetwork(IVB, NetworkId.OEBB);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, IVB);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, IVB);
|
||||
|
||||
// 2018-11-05: migrate NRI to use RT
|
||||
final String NRI = "NRI";
|
||||
migrateSelectedNetwork(NRI, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, NRI);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, NRI);
|
||||
|
||||
// 2018-12-06: migrate VAGFR to use NVBW
|
||||
final String VAGFR = "VAGFR";
|
||||
migrateSelectedNetwork(VAGFR, NetworkId.NVBW);
|
||||
FavoriteStationsProvider.migrateFavoriteStations(this, VAGFR, NetworkId.NVBW);
|
||||
QueryHistoryProvider.migrateQueryHistory(this, VAGFR, NetworkId.NVBW);
|
||||
|
||||
// 2020-11-22: delete unused downloaded station databases
|
||||
final FilenameFilter filter = (dir, name) -> name.endsWith(".db") || name.endsWith(".db.meta");
|
||||
for (final File file : getFilesDir().listFiles(filter))
|
||||
file.delete();
|
||||
|
||||
// 2021-09-18: migrate SBB to use RT
|
||||
final String SBB = "SBB";
|
||||
migrateSelectedNetwork(SBB, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, SBB);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, SBB);
|
||||
// 2023-01-09: migrate VMS to use VVO
|
||||
final String VMS = "VMS";
|
||||
migrateSelectedNetwork(VMS, NetworkId.VVO);
|
||||
FavoriteStationsProvider.migrateFavoriteStations(this, VMS, NetworkId.VVO);
|
||||
QueryHistoryProvider.migrateQueryHistory(this, VMS, NetworkId.VVO);
|
||||
|
||||
// 2023-11-05: migrate TFI to use RT
|
||||
final String TFI = "TFI";
|
||||
migrateSelectedNetwork(TFI, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, TFI);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, TFI);
|
||||
|
||||
// 2023-11-16: migrate AVV to use AVV_AUGSBURG
|
||||
final String AVV = "AVV";
|
||||
migrateSelectedNetwork(AVV, NetworkId.AVV_AUGSBURG);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, AVV);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, AVV);
|
||||
|
||||
// 2023-12-17: migrate SNCB to use RT
|
||||
final String SNCB = "SNCB";
|
||||
migrateSelectedNetwork(SNCB, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, SNCB);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, SNCB);
|
||||
|
||||
// 2024-04-27: EFA-ID migration of MVV
|
||||
FavoriteStationsProvider.migrateFavoriteStationIds(this, NetworkId.MVV, "0", "10000", 91000000);
|
||||
QueryHistoryProvider.migrateQueryHistoryIds(this, NetworkId.MVV, "0", "10000", 91000000);
|
||||
|
||||
// 2024-08-09: migrate Finland to use RT
|
||||
final String FINLAND = "FINLAND";
|
||||
migrateSelectedNetwork(FINLAND, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, FINLAND);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, FINLAND);
|
||||
|
||||
// 2024-08-30: migrate Czech Republic to use RT
|
||||
final String CZECH_REPUBLIC = "CZECH_REPUBLIC";
|
||||
migrateSelectedNetwork(CZECH_REPUBLIC, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, CZECH_REPUBLIC);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, CZECH_REPUBLIC);
|
||||
|
||||
// 2024-08-30: migrate Italy to use RT
|
||||
final String IT = "IT";
|
||||
migrateSelectedNetwork(IT, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, IT);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, IT);
|
||||
|
||||
// 2024-08-30: migrate Paris to use RT
|
||||
final String PARIS = "PARIS";
|
||||
migrateSelectedNetwork(PARIS, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, PARIS);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, PARIS);
|
||||
|
||||
// 2024-08-30: migrate Spain to use RT
|
||||
final String SPAIN = "SPAIN";
|
||||
migrateSelectedNetwork(SPAIN, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, SPAIN);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, SPAIN);
|
||||
|
||||
// 2024-08-30: migrate Nicaragua to use RT
|
||||
final String NICARAGUA = "NICARAGUA";
|
||||
migrateSelectedNetwork(NICARAGUA, NetworkId.RT);
|
||||
FavoriteStationsProvider.deleteFavoriteStations(this, NICARAGUA);
|
||||
QueryHistoryProvider.deleteQueryHistory(this, NICARAGUA);
|
||||
|
||||
log.info("Migrations took {}", watch);
|
||||
|
||||
initNotificationManager();
|
||||
}
|
||||
|
||||
private void initLogging() {
|
||||
|
@ -178,20 +211,6 @@ public class Application extends android.app.Application {
|
|||
config.setUserAgentValue(getPackageName());
|
||||
}
|
||||
|
||||
private void initNotificationManager() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
final Stopwatch watch = Stopwatch.createStarted();
|
||||
final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
final NotificationChannel appwidget = new NotificationChannel(
|
||||
NearestFavoriteStationWidgetService.NOTIFICATION_CHANNEL_ID_APPWIDGET,
|
||||
getString(R.string.notification_channel_appwidget_name), NotificationManager.IMPORTANCE_LOW);
|
||||
nm.createNotificationChannel(appwidget);
|
||||
|
||||
log.info("created notification channels, took {}", watch);
|
||||
}
|
||||
}
|
||||
|
||||
private void migrateSelectedNetwork(final String fromName, final NetworkId to) {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
|
@ -214,13 +233,4 @@ public class Application extends android.app.Application {
|
|||
public static final int versionCode(final Application application) {
|
||||
return application.packageInfo().versionCode;
|
||||
}
|
||||
|
||||
public static final String versionFlavor(final Application application) {
|
||||
final String applicationVersion = versionName(application);
|
||||
final int applicationVersionSplit = applicationVersion.indexOf('-');
|
||||
if (applicationVersionSplit >= 0)
|
||||
return applicationVersion.substring(applicationVersionSplit + 1);
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,9 @@
|
|||
|
||||
package de.schildbach.oeffi;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.text.format.DateUtils;
|
||||
import androidx.activity.SystemBarStyle;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
import java.util.Locale;
|
||||
|
@ -30,8 +32,6 @@ public class Constants {
|
|||
public static final String PLAN_INDEX_FILENAME = "plans-index.txt";
|
||||
public static final String PLAN_STATIONS_FILENAME = "plans-stations.txt";
|
||||
|
||||
public static final String BITCOIN_ADDRESS = "bc1q8ruc8hanp7hrzfs48dvtuzz4ukmpe7cgsvvzrt";
|
||||
|
||||
public static final String REPORT_EMAIL = "oeffi.app@gmail.com";
|
||||
|
||||
public static final long LOCATION_UPDATE_FREQ_MS = 10 * DateUtils.SECOND_IN_MILLIS;
|
||||
|
@ -67,4 +67,6 @@ public class Constants {
|
|||
public static final String DESTINATION_ARROW_PREFIX = Character.toString(Constants.CHAR_RIGHTWARDS_ARROW)
|
||||
+ Constants.CHAR_THIN_SPACE;
|
||||
public static final String DESTINATION_ARROW_INVISIBLE_PREFIX = " ";
|
||||
|
||||
public static final SystemBarStyle STATUS_BAR_STYLE = SystemBarStyle.dark(Color.TRANSPARENT);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ package de.schildbach.oeffi;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
|
@ -33,7 +34,6 @@ import android.widget.ImageView.ScaleType;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import de.schildbach.oeffi.util.CheatSheet;
|
||||
import de.schildbach.oeffi.util.ToggleImageButton;
|
||||
|
||||
public class MyActionBar extends LinearLayout {
|
||||
|
@ -147,7 +147,8 @@ public class MyActionBar extends LinearLayout {
|
|||
if (descriptionRes != 0) {
|
||||
final String description = context.getString(descriptionRes);
|
||||
button.setContentDescription(description);
|
||||
CheatSheet.setup(button, description);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
button.setTooltipText(description);
|
||||
}
|
||||
addView(button, BUTTON_INSERT_INDEX, buttonParams);
|
||||
|
||||
|
@ -166,7 +167,8 @@ public class MyActionBar extends LinearLayout {
|
|||
if (descriptionRes != 0) {
|
||||
final String description = context.getString(descriptionRes);
|
||||
button.setContentDescription(description);
|
||||
CheatSheet.setup(button, description);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
button.setTooltipText(description);
|
||||
}
|
||||
addView(button, BUTTON_INSERT_INDEX, buttonParams);
|
||||
|
||||
|
@ -176,7 +178,8 @@ public class MyActionBar extends LinearLayout {
|
|||
public View addProgressButton() {
|
||||
progressAlwaysVisible = true;
|
||||
progressView.setVisibility(View.VISIBLE);
|
||||
CheatSheet.setup(progressButton);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
progressButton.setTooltipText(progressButton.getContentDescription());
|
||||
return getProgressButton();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,13 +17,11 @@
|
|||
|
||||
package de.schildbach.oeffi;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.text.format.DateUtils;
|
||||
|
@ -31,6 +29,8 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import de.schildbach.oeffi.network.NetworkResources;
|
||||
import de.schildbach.oeffi.util.ErrorReporter;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
|
@ -38,7 +38,7 @@ import de.schildbach.pte.dto.ResultHeader;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public abstract class OeffiActivity extends Activity {
|
||||
public abstract class OeffiActivity extends ComponentActivity {
|
||||
protected Application application;
|
||||
protected SharedPreferences prefs;
|
||||
|
||||
|
@ -46,12 +46,12 @@ public abstract class OeffiActivity extends Activity {
|
|||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this, Constants.STATUS_BAR_STYLE);
|
||||
super.onCreate(savedInstanceState);
|
||||
this.application = (Application) getApplication();
|
||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
ErrorReporter.getInstance().check(this, applicationVersionCode(), applicationVersionFlavor(),
|
||||
application.okHttpClient());
|
||||
ErrorReporter.getInstance().check(this, applicationVersionCode(), application.okHttpClient());
|
||||
}
|
||||
|
||||
protected void updateFragments(final int listFrameResId, final int mapFrameResId) {
|
||||
|
@ -100,10 +100,6 @@ public abstract class OeffiActivity extends Activity {
|
|||
return Application.versionCode(application);
|
||||
}
|
||||
|
||||
protected final String applicationVersionFlavor() {
|
||||
return Application.versionFlavor(application);
|
||||
}
|
||||
|
||||
protected final long applicationFirstInstallTime() {
|
||||
return application.packageInfo().firstInstallTime;
|
||||
}
|
||||
|
@ -157,10 +153,4 @@ public abstract class OeffiActivity extends Activity {
|
|||
|
||||
return str;
|
||||
}
|
||||
|
||||
@TargetApi(24)
|
||||
@Override
|
||||
public boolean isInMultiWindowMode() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && super.isInMultiWindowMode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,10 @@ import android.text.format.DateUtils;
|
|||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.MenuProvider;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -70,6 +71,7 @@ import okhttp3.Response;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
@ -90,6 +92,7 @@ public abstract class OeffiMainActivity extends OeffiActivity {
|
|||
|
||||
private DrawerLayout navigationDrawerLayout;
|
||||
private RecyclerView navigationDrawerListView;
|
||||
private MenuProvider navigationDrawerMenuProvider;
|
||||
private View navigationDrawerFooterView;
|
||||
private View navigationDrawerFooterHeartView;
|
||||
|
||||
|
@ -113,6 +116,86 @@ public abstract class OeffiMainActivity extends OeffiActivity {
|
|||
versionCode = applicationVersionCode();
|
||||
lastVersionCode = prefs.getInt(Constants.PREFS_KEY_LAST_VERSION, 0);
|
||||
|
||||
navigationDrawerMenuProvider = new MenuProvider() {
|
||||
@Override
|
||||
public void onCreateMenu(final Menu menu, final MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.global_options, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareMenu(final Menu menu) {
|
||||
final MenuItem stationsItem = menu.findItem(R.id.global_options_stations);
|
||||
stationsItem.setChecked(OeffiMainActivity.this instanceof StationsActivity);
|
||||
final MenuItem directionsItem = menu.findItem(R.id.global_options_directions);
|
||||
directionsItem.setChecked(OeffiMainActivity.this instanceof DirectionsActivity);
|
||||
final MenuItem plansItem = menu.findItem(R.id.global_options_plans);
|
||||
plansItem.setChecked(OeffiMainActivity.this instanceof PlansPickerActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.global_options_stations: {
|
||||
if (OeffiMainActivity.this instanceof StationsActivity)
|
||||
return true;
|
||||
final Intent intent = new Intent(OeffiMainActivity.this, StationsActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
overridePendingTransition(R.anim.enter_from_left, R.anim.exit_to_right);
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_directions: {
|
||||
if (OeffiMainActivity.this instanceof DirectionsActivity)
|
||||
return true;
|
||||
final Intent intent = new Intent(OeffiMainActivity.this, DirectionsActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
if (OeffiMainActivity.this instanceof StationsActivity)
|
||||
overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left);
|
||||
else
|
||||
overridePendingTransition(R.anim.enter_from_left, R.anim.exit_to_right);
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_plans: {
|
||||
if (OeffiMainActivity.this instanceof PlansPickerActivity)
|
||||
return true;
|
||||
final Intent intent = new Intent(OeffiMainActivity.this, PlansPickerActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left);
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_donate: {
|
||||
PreferenceActivity.start(OeffiMainActivity.this, DonateFragment.class.getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_report_bug: {
|
||||
ErrorReporter.sendBugMail(OeffiMainActivity.this, application.packageInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_preferences: {
|
||||
PreferenceActivity.start(OeffiMainActivity.this);
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_about: {
|
||||
PreferenceActivity.start(OeffiMainActivity.this, AboutFragment.class.getName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
if (prefsGetNetwork() == null) {
|
||||
NetworkPickerActivity.start(this);
|
||||
|
||||
|
@ -177,13 +260,13 @@ public abstract class OeffiMainActivity extends OeffiActivity {
|
|||
|
||||
final NavigationMenuAdapter menuAdapter = new NavigationMenuAdapter(this,
|
||||
item -> {
|
||||
onOptionsItemSelected(item);
|
||||
navigationDrawerMenuProvider.onMenuItemSelected(item);
|
||||
navigationDrawerLayout.closeDrawers();
|
||||
return false;
|
||||
});
|
||||
final Menu menu = menuAdapter.getMenu();
|
||||
onCreateOptionsMenu(menu);
|
||||
onPrepareOptionsMenu(menu);
|
||||
navigationDrawerMenuProvider.onCreateMenu(menu, getMenuInflater());
|
||||
navigationDrawerMenuProvider.onPrepareMenu(menu);
|
||||
|
||||
navigationDrawerListView.setLayoutManager(new LinearLayoutManager(this));
|
||||
navigationDrawerListView
|
||||
|
@ -236,99 +319,6 @@ public abstract class OeffiMainActivity extends OeffiActivity {
|
|||
navigationDrawerLayout.closeDrawer(Gravity.LEFT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.global_options, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(final Menu menu) {
|
||||
final MenuItem stationsItem = menu.findItem(R.id.global_options_stations);
|
||||
stationsItem.setChecked(this instanceof StationsActivity);
|
||||
|
||||
final MenuItem directionsItem = menu.findItem(R.id.global_options_directions);
|
||||
directionsItem.setChecked(this instanceof DirectionsActivity);
|
||||
|
||||
final MenuItem plansItem = menu.findItem(R.id.global_options_plans);
|
||||
plansItem.setChecked(this instanceof PlansPickerActivity);
|
||||
|
||||
final MenuItem donateItem = menu.findItem(R.id.global_options_donate);
|
||||
donateItem.setVisible(Variants.ENABLE_DONATE);
|
||||
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.global_options_stations: {
|
||||
if (this instanceof StationsActivity)
|
||||
return true;
|
||||
|
||||
final Intent intent = new Intent(this, StationsActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
overridePendingTransition(R.anim.enter_from_left, R.anim.exit_to_right);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_directions: {
|
||||
if (this instanceof DirectionsActivity)
|
||||
return true;
|
||||
|
||||
final Intent intent = new Intent(this, DirectionsActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
if (this instanceof StationsActivity)
|
||||
overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left);
|
||||
else
|
||||
overridePendingTransition(R.anim.enter_from_left, R.anim.exit_to_right);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_plans: {
|
||||
if (this instanceof PlansPickerActivity)
|
||||
return true;
|
||||
|
||||
final Intent intent = new Intent(this, PlansPickerActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
overridePendingTransition(R.anim.enter_from_right, R.anim.exit_to_left);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_donate: {
|
||||
if (Variants.ENABLE_DONATE)
|
||||
PreferenceActivity.start(this, DonateFragment.class.getName());
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_report_bug: {
|
||||
ErrorReporter.sendBugMail(this, application.packageInfo());
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_preferences: {
|
||||
PreferenceActivity.start(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
case R.id.global_options_about: {
|
||||
PreferenceActivity.start(this, AboutFragment.class.getName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(final int keyCode, final KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
|
@ -351,18 +341,11 @@ public abstract class OeffiMainActivity extends OeffiActivity {
|
|||
|
||||
private void downloadAndProcessMessages(final String network) {
|
||||
final HttpUrl.Builder remoteUrl = Constants.MESSAGES_BASE_URL.newBuilder();
|
||||
final StringBuilder remoteFileName = new StringBuilder("messages");
|
||||
final String flavor = applicationVersionFlavor();
|
||||
if (flavor != null)
|
||||
remoteFileName.append('-').append(flavor);
|
||||
remoteFileName.append(".txt");
|
||||
remoteUrl.addPathSegment(remoteFileName.toString());
|
||||
remoteUrl.addPathSegment("messages.txt");
|
||||
final String installerPackageName = Installer.installerPackageName(this);
|
||||
if (installerPackageName != null)
|
||||
remoteUrl.addEncodedQueryParameter("installer", installerPackageName);
|
||||
remoteUrl.addQueryParameter("version", Integer.toString(versionCode));
|
||||
if (flavor != null)
|
||||
remoteUrl.addQueryParameter("flavor", flavor);
|
||||
remoteUrl.addQueryParameter("sdk", Integer.toString(Build.VERSION.SDK_INT));
|
||||
remoteUrl.addQueryParameter("task", taskName());
|
||||
final File localFile = new File(getFilesDir(), "messages.txt");
|
||||
|
|
|
@ -58,11 +58,14 @@ import android.widget.Filter;
|
|||
import android.widget.Filterable;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContract;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.common.base.Throwables;
|
||||
|
@ -116,6 +119,7 @@ import org.osmdroid.views.overlay.Overlay;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -132,8 +136,8 @@ import java.util.LinkedList;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class DirectionsActivity extends OeffiMainActivity implements ActivityCompat.OnRequestPermissionsResultCallback,
|
||||
QueryHistoryClickListener, QueryHistoryContextMenuItemListener {
|
||||
public class DirectionsActivity extends OeffiMainActivity implements QueryHistoryClickListener,
|
||||
QueryHistoryContextMenuItemListener {
|
||||
private ConnectivityManager connectivityManager;
|
||||
private LocationManager locationManager;
|
||||
|
||||
|
@ -167,25 +171,72 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
|
||||
private static final int DIALOG_CLEAR_HISTORY = 1;
|
||||
|
||||
private static final int REQUEST_CODE_CONTACTS_PERMISSION_FROM = 1;
|
||||
private static final int REQUEST_CODE_CONTACTS_PERMISSION_VIA = 2;
|
||||
private static final int REQUEST_CODE_CONTACTS_PERMISSION_TO = 3;
|
||||
private static final int REQUEST_CODE_LOCATION_PERMISSION_FROM = 4;
|
||||
private static final int REQUEST_CODE_LOCATION_PERMISSION_VIA = 5;
|
||||
private static final int REQUEST_CODE_LOCATION_PERMISSION_TO = 6;
|
||||
private static final int REQUEST_CODE_PICK_CONTACT_FROM = 7;
|
||||
private static final int REQUEST_CODE_PICK_CONTACT_VIA = 8;
|
||||
private static final int REQUEST_CODE_PICK_CONTACT_TO = 9;
|
||||
private static final int REQUEST_CODE_PICK_STATION_FROM = 10;
|
||||
private static final int REQUEST_CODE_PICK_STATION_VIA = 11;
|
||||
private static final int REQUEST_CODE_PICK_STATION_TO = 12;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DirectionsActivity.class);
|
||||
|
||||
private static final String INTENT_EXTRA_FROM_LOCATION = DirectionsActivity.class.getName() + ".from_location";
|
||||
private static final String INTENT_EXTRA_TO_LOCATION = DirectionsActivity.class.getName() + ".to_location";
|
||||
private static final String INTENT_EXTRA_TIME_SPEC = DirectionsActivity.class.getName() + ".time_spec";
|
||||
private static final Intent INTENT_PICK_CONTACTS = new Intent(Intent.ACTION_PICK, CommonDataKinds.StructuredPostal.CONTENT_URI);
|
||||
|
||||
private static class PickContact extends ActivityResultContract<Void, Uri> {
|
||||
@Override
|
||||
public Intent createIntent(final Context context, Void unused) {
|
||||
return new Intent(Intent.ACTION_PICK, CommonDataKinds.StructuredPostal.CONTENT_URI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri parseResult(final int resultCode, @Nullable final Intent intent) {
|
||||
if (resultCode == Activity.RESULT_OK && intent != null)
|
||||
return intent.getData();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private final ActivityResultLauncher<String> requestLocationPermissionFromLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
|
||||
if (granted)
|
||||
viewFromLocation.acquireLocation();
|
||||
});
|
||||
private final ActivityResultLauncher<String> requestLocationPermissionViaLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
|
||||
if (granted)
|
||||
viewViaLocation.acquireLocation();
|
||||
});
|
||||
private final ActivityResultLauncher<String> requestLocationPermissionToLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
|
||||
if (granted)
|
||||
viewToLocation.acquireLocation();
|
||||
});
|
||||
private final ActivityResultLauncher<Void> pickContactFromLauncher =
|
||||
registerForActivityResult(new PickContact(), contentUri -> {
|
||||
if (contentUri != null)
|
||||
resultPickContact(contentUri, viewFromLocation);
|
||||
});
|
||||
private final ActivityResultLauncher<Void> pickContactViaLauncher =
|
||||
registerForActivityResult(new PickContact(), contentUri -> {
|
||||
if (contentUri != null)
|
||||
resultPickContact(contentUri, viewViaLocation);
|
||||
});
|
||||
private final ActivityResultLauncher<Void> pickContactToLauncher =
|
||||
registerForActivityResult(new PickContact(), contentUri -> {
|
||||
if (contentUri != null)
|
||||
resultPickContact(contentUri, viewToLocation);
|
||||
});
|
||||
private final ActivityResultLauncher<NetworkId> pickStationFromLauncher =
|
||||
registerForActivityResult(new FavoriteStationsActivity.PickFavoriteStation(), contentUri -> {
|
||||
if (contentUri != null)
|
||||
resultPickStation(contentUri, viewFromLocation);
|
||||
});
|
||||
private final ActivityResultLauncher<NetworkId> pickStationViaLauncher =
|
||||
registerForActivityResult(new FavoriteStationsActivity.PickFavoriteStation(), contentUri -> {
|
||||
if (contentUri != null)
|
||||
resultPickStation(contentUri, viewViaLocation);
|
||||
});
|
||||
private final ActivityResultLauncher<NetworkId> pickStationToLauncher =
|
||||
registerForActivityResult(new FavoriteStationsActivity.PickFavoriteStation(), contentUri -> {
|
||||
if (contentUri != null)
|
||||
resultPickStation(contentUri, viewToLocation);
|
||||
});
|
||||
|
||||
public static void start(final Context context, @Nullable final Location fromLocation,
|
||||
@Nullable final Location toLocation, @Nullable final TimeSpec timeSpec, final int intentFlags) {
|
||||
|
@ -201,19 +252,17 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
|
||||
private class LocationContextMenuItemClickListener implements PopupMenu.OnMenuItemClickListener {
|
||||
private final LocationView locationView;
|
||||
private final int contactsPermissionRequestCode;
|
||||
private final int locationPermissionRequestCode;
|
||||
private final int pickContactRequestCode;
|
||||
private final int pickStationRequestCode;
|
||||
private final ActivityResultLauncher<String> requestLocationPermissionLauncher;
|
||||
private final ActivityResultLauncher<Void> pickContactLauncher;
|
||||
private final ActivityResultLauncher<NetworkId> pickStationLauncher;
|
||||
|
||||
public LocationContextMenuItemClickListener(final LocationView locationView,
|
||||
final int contactsPermissionRequestCode, final int locationPermissionRequestCode,
|
||||
final int pickContactRequestCode, final int pickStationRequestCode) {
|
||||
final ActivityResultLauncher<String> requestLocationPermissionLauncher,
|
||||
final ActivityResultLauncher<Void> pickContactLauncher, final ActivityResultLauncher<NetworkId> pickStationLauncher) {
|
||||
this.locationView = locationView;
|
||||
this.contactsPermissionRequestCode = contactsPermissionRequestCode;
|
||||
this.locationPermissionRequestCode = locationPermissionRequestCode;
|
||||
this.pickContactRequestCode = pickContactRequestCode;
|
||||
this.pickStationRequestCode = pickStationRequestCode;
|
||||
this.requestLocationPermissionLauncher = requestLocationPermissionLauncher;
|
||||
this.pickContactLauncher = pickContactLauncher;
|
||||
this.pickStationLauncher = pickStationLauncher;
|
||||
}
|
||||
|
||||
public boolean onMenuItemClick(final MenuItem item) {
|
||||
|
@ -222,20 +271,14 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
|
||||
locationView.acquireLocation();
|
||||
else
|
||||
ActivityCompat.requestPermissions(DirectionsActivity.this,
|
||||
new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, locationPermissionRequestCode);
|
||||
requestLocationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.directions_location_contact) {
|
||||
if (ContextCompat.checkSelfPermission(DirectionsActivity.this,
|
||||
Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED)
|
||||
startActivityForResult(INTENT_PICK_CONTACTS, pickContactRequestCode);
|
||||
else
|
||||
ActivityCompat.requestPermissions(DirectionsActivity.this,
|
||||
new String[] { Manifest.permission.READ_CONTACTS }, contactsPermissionRequestCode);
|
||||
pickContactLauncher.launch(null);
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.directions_location_favorite_station) {
|
||||
if (network != null)
|
||||
FavoriteStationsActivity.startForResult(DirectionsActivity.this, pickStationRequestCode, network);
|
||||
pickStationLauncher.launch(network);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -266,10 +309,11 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
|
||||
setContentView(R.layout.directions_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
final MyActionBar actionBar = getMyActionBar();
|
||||
|
@ -318,15 +362,13 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
viewFromLocation.setAdapter(autoCompleteAdapter);
|
||||
viewFromLocation.setListener(locationChangeListener);
|
||||
viewFromLocation.setContextMenuItemClickListener(new LocationContextMenuItemClickListener(viewFromLocation,
|
||||
REQUEST_CODE_CONTACTS_PERMISSION_FROM, REQUEST_CODE_LOCATION_PERMISSION_FROM,
|
||||
REQUEST_CODE_PICK_CONTACT_FROM, REQUEST_CODE_PICK_STATION_FROM));
|
||||
requestLocationPermissionFromLauncher, pickContactFromLauncher, pickStationFromLauncher));
|
||||
|
||||
viewViaLocation = findViewById(R.id.directions_via);
|
||||
viewViaLocation.setAdapter(autoCompleteAdapter);
|
||||
viewViaLocation.setListener(locationChangeListener);
|
||||
viewViaLocation.setContextMenuItemClickListener(new LocationContextMenuItemClickListener(viewViaLocation,
|
||||
REQUEST_CODE_CONTACTS_PERMISSION_VIA, REQUEST_CODE_LOCATION_PERMISSION_VIA,
|
||||
REQUEST_CODE_PICK_CONTACT_VIA, REQUEST_CODE_PICK_STATION_VIA));
|
||||
requestLocationPermissionViaLauncher, pickContactViaLauncher, pickStationViaLauncher));
|
||||
|
||||
viewToLocation = findViewById(R.id.directions_to);
|
||||
viewToLocation.setAdapter(autoCompleteAdapter);
|
||||
|
@ -343,8 +385,7 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
}
|
||||
});
|
||||
viewToLocation.setContextMenuItemClickListener(new LocationContextMenuItemClickListener(viewToLocation,
|
||||
REQUEST_CODE_CONTACTS_PERMISSION_TO, REQUEST_CODE_LOCATION_PERMISSION_TO,
|
||||
REQUEST_CODE_PICK_CONTACT_TO, REQUEST_CODE_PICK_STATION_TO));
|
||||
requestLocationPermissionToLauncher, pickContactToLauncher, pickStationToLauncher));
|
||||
|
||||
viewProducts = findViewById(R.id.directions_products);
|
||||
viewProductToggles.add(findViewById(R.id.directions_products_i));
|
||||
|
@ -418,10 +459,11 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
viewQueryHistoryList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
|
||||
queryHistoryListAdapter = new QueryHistoryAdapter(this, network, this, this);
|
||||
viewQueryHistoryList.setAdapter(queryHistoryListAdapter);
|
||||
viewQueryHistoryList.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(viewQueryHistoryList, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(),
|
||||
insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
viewQueryHistoryEmpty = findViewById(R.id.directions_query_history_empty);
|
||||
|
@ -508,15 +550,17 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
});
|
||||
final TextView mapDisclaimerView = findViewById(R.id.directions_map_disclaimer);
|
||||
mapDisclaimerView.setText(mapView.getTileProvider().getTileSource().getCopyrightNotice());
|
||||
mapDisclaimerView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0,0,0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mapDisclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
final ZoomControls zoom = findViewById(R.id.directions_map_zoom);
|
||||
zoom.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(zoom, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
mapView.setZoomControls(zoom);
|
||||
|
||||
|
@ -1132,75 +1176,20 @@ public class DirectionsActivity extends OeffiMainActivity implements ActivityCom
|
|||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(final int requestCode, final int resultCode, final Intent result) {
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
switch (requestCode) {
|
||||
case (REQUEST_CODE_PICK_CONTACT_FROM):
|
||||
resultPickContact(result, viewFromLocation);
|
||||
break;
|
||||
|
||||
case (REQUEST_CODE_PICK_CONTACT_VIA):
|
||||
resultPickContact(result, viewViaLocation);
|
||||
break;
|
||||
|
||||
case (REQUEST_CODE_PICK_CONTACT_TO):
|
||||
resultPickContact(result, viewToLocation);
|
||||
break;
|
||||
|
||||
case (REQUEST_CODE_PICK_STATION_FROM):
|
||||
resultPickStation(result, viewFromLocation);
|
||||
break;
|
||||
|
||||
case (REQUEST_CODE_PICK_STATION_VIA):
|
||||
resultPickStation(result, viewViaLocation);
|
||||
break;
|
||||
|
||||
case (REQUEST_CODE_PICK_STATION_TO):
|
||||
resultPickStation(result, viewToLocation);
|
||||
break;
|
||||
}
|
||||
private void resultPickContact(final Uri contentUri, final LocationView targetLocationView) {
|
||||
final Cursor c = managedQuery(contentUri, null, null, null, null);
|
||||
if (c.moveToFirst()) {
|
||||
final String data = c
|
||||
.getString(c.getColumnIndexOrThrow(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS));
|
||||
final Location location = new Location(LocationType.ADDRESS, null, null, data.replace("\n", " "));
|
||||
targetLocationView.setLocation(location);
|
||||
log.info("Picked {} from contacts", location);
|
||||
requestFocusFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
|
||||
final int[] grantResults) {
|
||||
if (requestCode == REQUEST_CODE_CONTACTS_PERMISSION_FROM)
|
||||
startActivityForResult(INTENT_PICK_CONTACTS, REQUEST_CODE_PICK_CONTACT_FROM);
|
||||
else if (requestCode == REQUEST_CODE_CONTACTS_PERMISSION_VIA)
|
||||
startActivityForResult(INTENT_PICK_CONTACTS, REQUEST_CODE_PICK_CONTACT_VIA);
|
||||
else if (requestCode == REQUEST_CODE_CONTACTS_PERMISSION_TO)
|
||||
startActivityForResult(INTENT_PICK_CONTACTS, REQUEST_CODE_PICK_CONTACT_TO);
|
||||
else if (requestCode == REQUEST_CODE_LOCATION_PERMISSION_FROM)
|
||||
viewFromLocation.acquireLocation();
|
||||
else if (requestCode == REQUEST_CODE_LOCATION_PERMISSION_VIA)
|
||||
viewViaLocation.acquireLocation();
|
||||
else if (requestCode == REQUEST_CODE_LOCATION_PERMISSION_TO)
|
||||
viewToLocation.acquireLocation();
|
||||
}
|
||||
|
||||
private void resultPickContact(final Intent result, final LocationView targetLocationView) {
|
||||
try {
|
||||
final Cursor c = managedQuery(result.getData(), null, null, null, null);
|
||||
if (c.moveToFirst()) {
|
||||
final String data = c
|
||||
.getString(c.getColumnIndexOrThrow(CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS));
|
||||
final Location location = new Location(LocationType.ADDRESS, null, null, data.replace("\n", " "));
|
||||
targetLocationView.setLocation(location);
|
||||
log.info("Picked {} from contacts", location);
|
||||
requestFocusFirst();
|
||||
}
|
||||
} catch (final SecurityException x) {
|
||||
new Toast(this).longToast(R.string.directions_location_choose_error_permission, x.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void resultPickStation(final Intent result, final LocationView targetLocationView) {
|
||||
final Cursor c = managedQuery(result.getData(), null, null, null, null);
|
||||
private void resultPickStation(final Uri contentUri, final LocationView targetLocationView) {
|
||||
final Cursor c = managedQuery(contentUri, null, null, null, null);
|
||||
if (c.moveToFirst()) {
|
||||
final Location location = FavoriteStationsProvider.getLocation(c);
|
||||
targetLocationView.setLocation(location);
|
||||
|
|
|
@ -30,7 +30,8 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Process;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.google.common.base.Throwables;
|
||||
import de.schildbach.oeffi.Constants;
|
||||
|
@ -58,8 +59,7 @@ import org.slf4j.LoggerFactory;
|
|||
import javax.net.ssl.SSLException;
|
||||
import java.util.Set;
|
||||
|
||||
public class DirectionsShortcutActivity extends OeffiActivity
|
||||
implements ActivityCompat.OnRequestPermissionsResultCallback, LocationHelper.Callback {
|
||||
public class DirectionsShortcutActivity extends OeffiActivity implements LocationHelper.Callback {
|
||||
public static final String INTENT_EXTRA_NETWORK = "network";
|
||||
public static final String INTENT_EXTRA_TYPE = "type";
|
||||
public static final String INTENT_EXTRA_ID = "stationid";
|
||||
|
@ -76,10 +76,16 @@ public class DirectionsShortcutActivity extends OeffiActivity
|
|||
private final Handler handler = new Handler();
|
||||
private QueryTripsRunnable queryTripsRunnable;
|
||||
|
||||
private static final int REQUEST_CODE_REQUEST_LOCATION_PERMISSION = 1;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(DirectionsShortcutActivity.class);
|
||||
|
||||
private final ActivityResultLauncher<String> requestPermissionLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
|
||||
if (granted)
|
||||
maybeStartLocation();
|
||||
else
|
||||
errorDialog(R.string.acquire_location_no_permission);
|
||||
});
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -94,8 +100,7 @@ public class DirectionsShortcutActivity extends OeffiActivity
|
|||
Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED)
|
||||
maybeStartLocation();
|
||||
else
|
||||
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_FINE_LOCATION },
|
||||
REQUEST_CODE_REQUEST_LOCATION_PERMISSION);
|
||||
requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,17 +110,6 @@ public class DirectionsShortcutActivity extends OeffiActivity
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
|
||||
final int[] grantResults) {
|
||||
if (requestCode == REQUEST_CODE_REQUEST_LOCATION_PERMISSION) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
maybeStartLocation();
|
||||
else
|
||||
errorDialog(R.string.acquire_location_no_permission);
|
||||
}
|
||||
}
|
||||
|
||||
public void maybeStartLocation() {
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
|
||||
|
|
|
@ -41,7 +41,6 @@ import android.widget.FrameLayout;
|
|||
import android.widget.ListAdapter;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView.OnEditorActionListener;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.common.base.Strings;
|
||||
import de.schildbach.oeffi.Constants;
|
||||
import de.schildbach.oeffi.R;
|
||||
|
@ -53,6 +52,7 @@ import de.schildbach.pte.dto.Location;
|
|||
import de.schildbach.pte.dto.LocationType;
|
||||
import de.schildbach.pte.dto.Point;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Locale;
|
||||
|
||||
public class LocationView extends FrameLayout implements LocationHelper.Callback {
|
||||
|
|
|
@ -44,13 +44,15 @@ import android.util.DisplayMetrics;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TableLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import de.schildbach.oeffi.Constants;
|
||||
import de.schildbach.oeffi.LocationAware;
|
||||
|
@ -187,10 +189,11 @@ public class TripDetailsActivity extends OeffiActivity implements LocationListen
|
|||
scheduleTripIntent = scheduleTripIntent(trip);
|
||||
|
||||
setContentView(R.layout.directions_trip_details_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
final MyActionBar actionBar = getMyActionBar();
|
||||
|
@ -283,9 +286,11 @@ public class TripDetailsActivity extends OeffiActivity implements LocationListen
|
|||
((TextView) findViewById(R.id.directions_trip_details_footer))
|
||||
.setText(Html.fromHtml(getString(R.string.directions_trip_details_realtime)));
|
||||
|
||||
findViewById(R.id.directions_trip_details_disclaimer_group).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
final View disclaimerView = findViewById(R.id.directions_trip_details_disclaimer_group);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(disclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
final TextView disclaimerSourceView = findViewById(R.id.directions_trip_details_disclaimer_source);
|
||||
updateDisclaimerSource(disclaimerSourceView, network.name(), null);
|
||||
|
@ -314,9 +319,10 @@ public class TripDetailsActivity extends OeffiActivity implements LocationListen
|
|||
});
|
||||
final TextView mapDisclaimerView = findViewById(R.id.directions_trip_details_map_disclaimer);
|
||||
mapDisclaimerView.setText(mapView.getTileProvider().getTileSource().getCopyrightNotice());
|
||||
mapDisclaimerView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0,0,0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mapDisclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -366,11 +372,6 @@ public class TripDetailsActivity extends OeffiActivity implements LocationListen
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(final Configuration config) {
|
||||
super.onConfigurationChanged(config);
|
||||
|
|
|
@ -41,7 +41,6 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
import android.widget.Adapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.common.base.Preconditions;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.pte.dto.Line;
|
||||
|
@ -53,6 +52,7 @@ import de.schildbach.pte.dto.Trip.Individual;
|
|||
import de.schildbach.pte.dto.Trip.Leg;
|
||||
import de.schildbach.pte.dto.Trip.Public;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
|
|
@ -31,7 +31,9 @@ import android.text.format.DateUtils;
|
|||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Ordering;
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
|
@ -54,6 +56,7 @@ import de.schildbach.pte.exception.SessionExpiredException;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.net.ssl.SSLException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -130,10 +133,11 @@ public class TripsOverviewActivity extends OeffiActivity {
|
|||
final Uri historyUri = historyUriStr != null ? Uri.parse(historyUriStr) : null;
|
||||
|
||||
setContentView(R.layout.directions_trip_overview_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
final MyActionBar actionBar = getMyActionBar();
|
||||
|
@ -164,9 +168,11 @@ public class TripsOverviewActivity extends OeffiActivity {
|
|||
});
|
||||
barView.setOnScrollListener(() -> handler.post(checkMoreRunnable));
|
||||
|
||||
findViewById(R.id.directions_trip_overview_disclaimer_group).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
final View disclaimerView = findViewById(R.id.directions_trip_overview_disclaimer_group);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(disclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
processResult(result, dep);
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
|
||||
package de.schildbach.oeffi.directions.list;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface QueryHistoryContextMenuItemListener {
|
||||
boolean onQueryHistoryContextMenuItemClick(int adapterPosition, Location from, Location to,
|
||||
@Nullable byte[] serializedSavedTrip, int menuItemId, @Nullable Location menuItemLocation);
|
||||
|
|
|
@ -18,8 +18,6 @@
|
|||
package de.schildbach.oeffi.network;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -27,10 +25,10 @@ import android.content.SharedPreferences;
|
|||
import android.content.pm.PackageManager;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.location.Address;
|
||||
import android.location.Criteria;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
|
@ -40,8 +38,14 @@ import android.view.KeyEvent;
|
|||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.schildbach.oeffi.AreaAware;
|
||||
|
@ -57,7 +61,6 @@ import de.schildbach.oeffi.network.list.NetworksAdapter;
|
|||
import de.schildbach.oeffi.util.DividerItemDecoration;
|
||||
import de.schildbach.oeffi.util.GeocoderThread;
|
||||
import de.schildbach.oeffi.util.LocationHelper;
|
||||
import de.schildbach.pte.AbstractNavitiaProvider;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import de.schildbach.pte.NetworkProvider;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
|
@ -75,8 +78,8 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class NetworkPickerActivity extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback,
|
||||
LocationHelper.Callback, NetworkClickListener, NetworkContextMenuItemListener {
|
||||
public class NetworkPickerActivity extends ComponentActivity implements LocationHelper.Callback, NetworkClickListener,
|
||||
NetworkContextMenuItemListener {
|
||||
public static void start(final Context context) {
|
||||
final Intent intent = new Intent(context, NetworkPickerActivity.class);
|
||||
context.startActivity(intent);
|
||||
|
@ -102,12 +105,16 @@ public class NetworkPickerActivity extends Activity implements ActivityCompat.On
|
|||
private static final String INDEX_FILENAME = "networks.txt";
|
||||
private static final int MAX_LAST_NETWORKS = 3;
|
||||
|
||||
private static final int REQUEST_CODE_REQUEST_LOCATION_PERMISSION = 1;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NetworkPickerActivity.class);
|
||||
|
||||
private final ActivityResultLauncher<String> requestPermissionLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
|
||||
maybeStartLocation();
|
||||
});
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this, Constants.STATUS_BAR_STYLE);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
@ -119,10 +126,11 @@ public class NetworkPickerActivity extends Activity implements ActivityCompat.On
|
|||
backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
|
||||
setContentView(R.layout.network_picker_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
actionBar = findViewById(R.id.action_bar);
|
||||
|
@ -135,18 +143,19 @@ public class NetworkPickerActivity extends Activity implements ActivityCompat.On
|
|||
final String network = prefsGetNetwork();
|
||||
listAdapter = new NetworksAdapter(this, network, this, this);
|
||||
listView.setAdapter(listAdapter);
|
||||
listView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(),
|
||||
insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(listView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
mapView = findViewById(R.id.network_picker_map);
|
||||
final TextView mapDisclaimerView = findViewById(R.id.network_picker_map_disclaimer);
|
||||
mapDisclaimerView.setText(mapView.getTileProvider().getTileSource().getCopyrightNotice());
|
||||
mapDisclaimerView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mapDisclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
if (network != null) {
|
||||
|
@ -195,8 +204,7 @@ public class NetworkPickerActivity extends Activity implements ActivityCompat.On
|
|||
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
|
||||
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION },
|
||||
REQUEST_CODE_REQUEST_LOCATION_PERMISSION);
|
||||
requestPermissionLauncher.launch(Manifest.permission.ACCESS_COARSE_LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -233,13 +241,6 @@ public class NetworkPickerActivity extends Activity implements ActivityCompat.On
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
|
||||
final int[] grantResults) {
|
||||
if (requestCode == REQUEST_CODE_REQUEST_LOCATION_PERMISSION)
|
||||
maybeStartLocation();
|
||||
}
|
||||
|
||||
public void maybeStartLocation() {
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
|
||||
|
@ -481,10 +482,6 @@ public class NetworkPickerActivity extends Activity implements ActivityCompat.On
|
|||
|
||||
final NetworkProvider networkProvider = NetworkProviderFactory.provider(NetworkId.valueOf(network.id));
|
||||
|
||||
// workaround, because of network access for navitia
|
||||
if (AbstractNavitiaProvider.class.isAssignableFrom(networkProvider.getClass()))
|
||||
return false;
|
||||
|
||||
boolean inArea = false;
|
||||
|
||||
final Point[] area = getArea(networkProvider);
|
||||
|
@ -575,10 +572,4 @@ public class NetworkPickerActivity extends Activity implements ActivityCompat.On
|
|||
actionBar.setBackgroundColor(color);
|
||||
setTaskDescription(new TaskDescription(null, null, color));
|
||||
}
|
||||
|
||||
@TargetApi(24)
|
||||
@Override
|
||||
public boolean isInMultiWindowMode() {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && super.isInMultiWindowMode();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,23 +18,21 @@
|
|||
package de.schildbach.oeffi.network;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import de.schildbach.pte.AbstractNetworkProvider;
|
||||
import de.schildbach.pte.AvvAachenProvider;
|
||||
import de.schildbach.pte.AvvProvider;
|
||||
import de.schildbach.pte.AvvAugsburgProvider;
|
||||
import de.schildbach.pte.BartProvider;
|
||||
import de.schildbach.pte.BayernProvider;
|
||||
import de.schildbach.pte.BsvagProvider;
|
||||
import de.schildbach.pte.BvgProvider;
|
||||
import de.schildbach.pte.CmtaProvider;
|
||||
import de.schildbach.pte.CzechRepublicProvider;
|
||||
import de.schildbach.pte.DbProvider;
|
||||
import de.schildbach.pte.DingProvider;
|
||||
import de.schildbach.pte.DsbProvider;
|
||||
import de.schildbach.pte.DubProvider;
|
||||
import de.schildbach.pte.FinlandProvider;
|
||||
import de.schildbach.pte.GvhProvider;
|
||||
import de.schildbach.pte.InvgProvider;
|
||||
import de.schildbach.pte.ItalyProvider;
|
||||
import de.schildbach.pte.KvvProvider;
|
||||
import de.schildbach.pte.LinzProvider;
|
||||
import de.schildbach.pte.LuProvider;
|
||||
|
@ -44,28 +42,22 @@ import de.schildbach.pte.MvvProvider;
|
|||
import de.schildbach.pte.NasaProvider;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import de.schildbach.pte.NetworkProvider;
|
||||
import de.schildbach.pte.NicaraguaProvider;
|
||||
import de.schildbach.pte.NsProvider;
|
||||
import de.schildbach.pte.NvbwProvider;
|
||||
import de.schildbach.pte.NvvProvider;
|
||||
import de.schildbach.pte.OebbProvider;
|
||||
import de.schildbach.pte.ParisProvider;
|
||||
import de.schildbach.pte.PlProvider;
|
||||
import de.schildbach.pte.RtProvider;
|
||||
import de.schildbach.pte.RtaChicagoProvider;
|
||||
import de.schildbach.pte.SeProvider;
|
||||
import de.schildbach.pte.ShProvider;
|
||||
import de.schildbach.pte.SncbProvider;
|
||||
import de.schildbach.pte.SpainProvider;
|
||||
import de.schildbach.pte.StvProvider;
|
||||
import de.schildbach.pte.SydneyProvider;
|
||||
import de.schildbach.pte.TfiProvider;
|
||||
import de.schildbach.pte.TlemProvider;
|
||||
import de.schildbach.pte.VbbProvider;
|
||||
import de.schildbach.pte.VblProvider;
|
||||
import de.schildbach.pte.VbnProvider;
|
||||
import de.schildbach.pte.VgnProvider;
|
||||
import de.schildbach.pte.VmsProvider;
|
||||
import de.schildbach.pte.VmtProvider;
|
||||
import de.schildbach.pte.VmvProvider;
|
||||
import de.schildbach.pte.VrnProvider;
|
||||
|
@ -84,9 +76,10 @@ import java.util.Map;
|
|||
|
||||
public final class NetworkProviderFactory {
|
||||
private static Map<NetworkId, NetworkProvider> providerCache = new HashMap<>();
|
||||
private static final BaseEncoding BASE64 = BaseEncoding.base64();
|
||||
|
||||
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36";
|
||||
private static final String NAVITIA_AUTHORIZATION = "577e5781-23ee-4ff0-a5b3-92e5b04887e5"; // oeffi@schildbach.de
|
||||
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:134.0) Gecko/20100101 Firefox/134.0";
|
||||
private static final byte[] VRS_CLIENT_CERTIFICATE = BASE64.decode("MIILOQIBAzCCCv8GCSqGSIb3DQEHAaCCCvAEggrsMIIK6DCCBZ8GCSqGSIb3DQEHBqCCBZAwggWMAgEAMIIFhQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYwDgQITP1aoTF3ISwCAggAgIIFWBba5Nms7ssWBgCkVFboVo4EQSGNe6GvJLvlAIAPGBieMyQOeJJwDJgl422+dzIAr+wxYNTgXMBMf7ZwPpVLUyCECGcePHfbLKyAK5CqvP+zYdGYc8oHF5JcukK2wm0oCxt4sRvPKAimFjU1NWFVzX8HY8dTYia59nOF1dk7LmfA5wI8Jr2YURB71lycHLvm4KbBl23AZmEgaAGWPcHhzPFfslo8arlixKGJqc02Tq9gA0+ZY/nkvNtl7fEbVJkHXF7QP7D5O7N5T6D2THyad9rqVdS499VwQ16b5lBTgV5vWD5Ctf5riuewc4aUziGLnukBrHgWOHK8TfsAhtTOrUerAFLNVB2jF6nBKbgywBXKYOBDhKX3MdVmt3srkq0/Ta2+bxUHfwRt17EQKFzboiNuraALs2jXrbSHvuO+pV2yj0WP/sX8d6KXf3XMFejynv7Os7sD0mQTcllsN9bf2oGVUnSaHT97RAekYxaF7LX+q94rhXmhpFPH/ILQEt92lF+nk+XlmhlGT9SUhwUJ6AKysFRY7si/ofE+8V4ZFHDnyjoUNDhOUYC/Z4I7YpozuPECPKNReTbPdHXqlBIiEx243gutskl8duiGYEv7TzraAq0Nag6Xk8YcXoyMXGC8wrecU7Uts9Tm2OBErAqxvFWXL9eN/EsYV8SB745tmU+T4EqJDDZQZnRAerg7Ms4iSKSbPNj/OtwpIptv43NWAtyzEEc6NxwwQTIJZL0v9jwB0mUY7TgM4a+VwMTBHcBNZH5+x8dpwh1H8MYh91UaBOidbc2PJeLtT4pIxYlcyYGl9LJa68WgzBkc7uJmETNOfKfdJEazLvH/jIRsLBwzPj/pbJDPER82wC8l5mmbOyNa/vgjsSAvm2uYDsV1fo8xdik3q/SFRHseIf2vQtybDXrytafUb9D6/0puTycMo5IfXegHvuwIJVhYFcqoCDX8VkkebHHWdWelr7yPealzjksddiJ9a4mksc4js3g7if5cQwYkfiVNE2FQukkjJx1xhgRCsnTRv1K0n0t1g4D5CD4oYjTBiYzgF/t2CqH85wNAVKnJmKNyt0Weqcf6GQwu0oVC+9IqSAiy07KvEbLxjjqcBarQjGKPSLmJeQ0x9X+9KIaEKG3gdN5l8ptlfHhML2wZsn0cTCBU1otOdLcu4QmBGf6DSTSCXcH4GGvlWdxjxdQ7Docmdp3hQBh8wY7jRST+YWcp5zQWkOpClFjKIKx2s+0sG7XM+LNPr2zSJZTyLcPlqdc9aam9LL3nf3CUtUNVrDaiyfTYhgpBHkwc+4P8MIsaZy8gowfBhovsYvfE5aFzF3rfLf30r31/ju/jkcfnWW995X+AJb8pcQuC6R7xJ82lZyPRpyfs96eCmizjIcAcL6Wz+SQEsUE3zNuH/ctpqhD5gCKXhJTj6sXjdiGNkYqPyxKX3blw8fdh+nIe3kBdC9deaw4S+5QYNKPSmdmQAAaOxOyzLi+DKgR9bV6SzWUAO/kWCdRaCdCDy9WS+6CQ2AVsQOSYv1vBMWkZ0u5/EHqPsb6y1wtXvE0/s7T4KZi7taP/72dDclPgNHsWCW5HbSaeyx83efu3fpX7i8tsWmr+QeeRuLGJ5z0NOBKasIKhCe3XPWZGNzKNca0WJk7UWepYFfiPv57tFj6Y0zautFHFNRgP+iu0hX7nNNn0AVXjuFFiZ/fwhjFmXExSYG9xSzcR5aJha0GEJ+MQbIZD7/Ay8GRmPFrrN8x40svTfiWu71qpxqsfco+2sKhJtBxJoO/cnjRz5PrtCdnqi4dYHtvOAyjaaF/3hQvDyiEoiDuxTPIVyjCCBUEGCSqGSIb3DQEHAaCCBTIEggUuMIIFKjCCBSYGCyqGSIb3DQEMCgECoIIE7jCCBOowHAYKKoZIhvcNAQwBAzAOBAg71M5exZmMVQICCAAEggTIohxJ2uLoi9RYzxe7t0XOHkTBSI+/Rn3oQNecNuMe/YNpMMsRCQjSOJToWHGayBQJmwSkMd3NP4QnDfqWFIxHbgnfj3FLTIyfkDIObzpfHwLCOrYHQxK9Zr4t/0SfEy/34uH40ZEiPe7Mnn/iTTZy37ecZgLsvlr6wp5Gao3oBjhKZlxJM043Hy9Dk1vtRCRIFCFbdGXtcLnuVKASc+GVw6QJKoXLerImV0U5Pg6khh0huTALEULuvq5cEIlKBNqyZ37cfb3Cvf9mWSTferBcUymGyHtdh+mHtVPb3ZycprtFmKcGMR9bXK0FJ63fERmXRHBN1ZKVC0beWVgcGybDQKdx9Y26UQLtO3xdZK0Eb3Kn8jVJG3sEJi2u3CLS4wD533+jj+b1uuL8Uj/aZy2UvrbIez48JStZgBGg+IhLK5keW7KV1lHiOVwZuWERpxzbNx7jaZRWIUCwN+aMJts1d5aY+wYvlJ9uk2lQc8qpIDIHHXHvyUEnk7jxw88gQjNgo1lvUHewiQk6VBwXX7EII0kLxdNfEpBT9RAdqURqy8dpoQemoc2zwce0e14G+IElJ1ES1j2jMYkYuggjpfUJBc34QrQI2a7UQwloUMwkdoi9nwgnpeL5G3Jyvgfxxf+D9xSXh8auH5IsdO0/enDGo/Xo+ygQ3tgY3dGI02frzRF24i4hFp/FAdbLjytjgCF0KIEXbJylEweZX2g61jL/fJVowJIA3wXDSuIBq9YRdpEA2OhgCdpwcz69W9T5lVfuJBgKOKcFKSQgDm0sEEkcUV9WR4CWfC9lZ+haHvNcrJBsRkHg6KKsV8PwwbUs2WeXl3NvGnJ/kSQbqJOLfURPziY9w4phupuSTAqmQIc0D4MSZLEjDcXKjg3ifFi4NlGLy+iyzGBoC1YZk1OOlO3uhKxxSD8FG6ncRGHEr8OU+2Yj/qubqZMpckPLXPdWbZB24bQxPTKGeQjFGlgt95H3/aRK9FzmBLc1FOe4qnT9chzbewsAnuho+F7Rqe36hPCZHlIrND0RCOdTAw7buJg6yPIbpDA41SpvS1F/BdFuDepf4yd0NWt4N46zUHmpxavv+2zmDiAUG95ZQ7AmkAA39tc+XtQv3IhLK6Wa7joM61jtau34td3vi1RvN2fPY2jQqOvKA2/hTVw5SzWCI0Tl7le6+ol1/QeUJfpjBZl6Ai+ydgVycSXuyq+MXB/UUEWo8RmlX8R9+y2KtCGV0TQjfX/um1D77LzurRO430m2pggcxmdCiFyl4CRp+rXhw7W6nGwLqZfD2msKthh+tn2QxoNII1oGHHsF7fxE/E4wm54IGtqfLM5pV/5hrqgVfTetABMLFEbtIHrxEDms80SyvsP2/JgelFFrs90wZr9QkLVBBQtZpwmLu39u24HlGXhZflXX0fmlHT2vN1e/EH43Nl/iPgZPYTj6fGGJFdaKNm0QlLym2M0btN3MNMXHETUoLDOg17AomH3NRvSIARu92qa48rX+SeCdF0NJ3VmA2I3Fl4A47epkmMcCzF078UVPC2eQ9M2NtxIAsqQnfIFfxirTuSCdeVS06n8KbMi7PG4Luc7IUPr4W3SQ9mY8XjFgRjVl86QpExzE6P5WZ/RDrgaypcDED6BvMSUwIwYJKoZIhvcNAQkVMRYEFKkQDH5bs77hmpmQ899BQPMX5lIDMDEwITAJBgUrDgMCGgUABBSqWv+fwvAy3ohpbmU2hfBpJbEejAQIPczIVgsfvYECAggA");
|
||||
|
||||
public static synchronized NetworkProvider provider(final NetworkId networkId) {
|
||||
final NetworkProvider cachedNetworkProvider = providerCache.get(networkId);
|
||||
|
@ -94,7 +87,8 @@ public final class NetworkProviderFactory {
|
|||
return cachedNetworkProvider;
|
||||
|
||||
final AbstractNetworkProvider networkProvider = forId(networkId);
|
||||
networkProvider.setUserAgent(USER_AGENT);
|
||||
if (networkId != NetworkId.PL)
|
||||
networkProvider.setUserAgent(USER_AGENT);
|
||||
providerCache.put(networkId, networkProvider);
|
||||
return networkProvider;
|
||||
}
|
||||
|
@ -103,8 +97,7 @@ public final class NetworkProviderFactory {
|
|||
if (networkId.equals(NetworkId.RT))
|
||||
return new RtProvider();
|
||||
else if (networkId.equals(NetworkId.DB))
|
||||
return new DbProvider("{\"type\":\"AID\",\"aid\":\"n91dB8Z77MLdoR0K\"}",
|
||||
"bdI8UVj40K5fvxwf".getBytes(Charsets.UTF_8));
|
||||
return new DbProvider();
|
||||
else if (networkId.equals(NetworkId.BVG))
|
||||
return new BvgProvider("{\"aid\":\"1Rxs112shyHLatUX4fofnmdxK\",\"type\":\"AID\"}");
|
||||
else if (networkId.equals(NetworkId.VBB))
|
||||
|
@ -119,8 +112,8 @@ public final class NetworkProviderFactory {
|
|||
else if (networkId.equals(NetworkId.INVG))
|
||||
return new InvgProvider("{\"type\":\"AID\",\"aid\":\"GITvwi3BGOmTQ2a5\"}",
|
||||
"ERxotxpwFT7uYRsI".getBytes(Charsets.UTF_8));
|
||||
else if (networkId.equals(NetworkId.AVV))
|
||||
return new AvvProvider();
|
||||
else if (networkId.equals(NetworkId.AVV_AUGSBURG))
|
||||
return new AvvAugsburgProvider("{\"type\":\"AID\",\"aid\":\"jK91AVVZU77xY5oH\"}");
|
||||
else if (networkId.equals(NetworkId.VGN))
|
||||
return new VgnProvider(HttpUrl.parse("https://efa.vgn.de/vgnExt_oeffi/"));
|
||||
else if (networkId.equals(NetworkId.VVM))
|
||||
|
@ -130,7 +123,7 @@ public final class NetworkProviderFactory {
|
|||
else if (networkId.equals(NetworkId.SH))
|
||||
return new ShProvider("{\"aid\":\"r0Ot9FLFNAFxijLW\",\"type\":\"AID\"}");
|
||||
else if (networkId.equals(NetworkId.GVH))
|
||||
return new GvhProvider(HttpUrl.parse("https://www.efa.de/app_oeffi/"));
|
||||
return new GvhProvider();
|
||||
else if (networkId.equals(NetworkId.BSVAG))
|
||||
return new BsvagProvider();
|
||||
else if (networkId.equals(NetworkId.VBN))
|
||||
|
@ -141,13 +134,11 @@ public final class NetworkProviderFactory {
|
|||
else if (networkId.equals(NetworkId.VMT))
|
||||
return new VmtProvider("{\"aid\":\"vj5d7i3g9m5d7e3\",\"type\":\"AID\"}");
|
||||
else if (networkId.equals(NetworkId.VVO))
|
||||
return new VvoProvider();
|
||||
else if (networkId.equals(NetworkId.VMS))
|
||||
return new VmsProvider(HttpUrl.parse("https://efa.vms.de/Oeffi/"));
|
||||
return new VvoProvider(HttpUrl.parse("https://efa.vvo-online.de/Oeffi/"));
|
||||
else if (networkId.equals(NetworkId.VRR))
|
||||
return new VrrProvider();
|
||||
else if (networkId.equals(NetworkId.VRS))
|
||||
return new VrsProvider();
|
||||
return new VrsProvider(VRS_CLIENT_CERTIFICATE);
|
||||
else if (networkId.equals(NetworkId.AVV_AACHEN))
|
||||
return new AvvAachenProvider("{\"id\":\"AVV_AACHEN\",\"l\":\"vs_oeffi\",\"type\":\"WEB\"}",
|
||||
"{\"type\":\"AID\",\"aid\":\"4vV1AcH3N511icH\"}");
|
||||
|
@ -173,20 +164,10 @@ public final class NetworkProviderFactory {
|
|||
return new LinzProvider();
|
||||
else if (networkId.equals(NetworkId.STV))
|
||||
return new StvProvider();
|
||||
else if (networkId.equals(NetworkId.CZECH_REPUBLIC))
|
||||
return new CzechRepublicProvider(NAVITIA_AUTHORIZATION);
|
||||
else if (networkId.equals(NetworkId.VBL))
|
||||
return new VblProvider();
|
||||
else if (networkId.equals(NetworkId.ZVV))
|
||||
return new ZvvProvider("{\"type\":\"AID\",\"aid\":\"hf7mcf9bv3nv8g5f\"}");
|
||||
else if (networkId.equals(NetworkId.IT))
|
||||
return new ItalyProvider(NAVITIA_AUTHORIZATION);
|
||||
else if (networkId.equals(NetworkId.PARIS))
|
||||
return new ParisProvider(NAVITIA_AUTHORIZATION);
|
||||
else if (networkId.equals(NetworkId.SPAIN))
|
||||
return new SpainProvider(NAVITIA_AUTHORIZATION);
|
||||
else if (networkId.equals(NetworkId.SNCB))
|
||||
return new SncbProvider("{\"type\":\"AID\",\"aid\":\"sncb-mobi\"}");
|
||||
else if (networkId.equals(NetworkId.LU))
|
||||
return new LuProvider("{\"type\":\"AID\",\"aid\":\"SkC81GuwuzL4e0\"}");
|
||||
else if (networkId.equals(NetworkId.NS))
|
||||
|
@ -195,16 +176,12 @@ public final class NetworkProviderFactory {
|
|||
return new DsbProvider("{\"type\":\"AID\",\"aid\":\"irkmpm9mdznstenr-android\"}");
|
||||
else if (networkId.equals(NetworkId.SE))
|
||||
return new SeProvider("{\"type\":\"AID\",\"aid\":\"h5o3n7f4t2m8l9x1\"}");
|
||||
else if (networkId.equals(NetworkId.FINLAND))
|
||||
return new FinlandProvider(NAVITIA_AUTHORIZATION);
|
||||
else if (networkId.equals(NetworkId.TLEM))
|
||||
return new TlemProvider();
|
||||
else if (networkId.equals(NetworkId.MERSEY))
|
||||
return new MerseyProvider();
|
||||
else if (networkId.equals(NetworkId.TFI))
|
||||
return new TfiProvider();
|
||||
else if (networkId.equals(NetworkId.PL))
|
||||
return new PlProvider();
|
||||
return new PlProvider("{\"type\":\"AID\",\"aid\":\"DrxJYtYZQpEBCtcb\"}");
|
||||
else if (networkId.equals(NetworkId.DUB))
|
||||
return new DubProvider();
|
||||
else if (networkId.equals(NetworkId.BART))
|
||||
|
@ -215,8 +192,6 @@ public final class NetworkProviderFactory {
|
|||
return new CmtaProvider("{\"type\":\"AID\",\"aid\":\"web9j2nak29uz41irb\"}");
|
||||
else if (networkId.equals(NetworkId.SYDNEY))
|
||||
return new SydneyProvider();
|
||||
else if (networkId.equals(NetworkId.NICARAGUA))
|
||||
return new NicaraguaProvider(NAVITIA_AUTHORIZATION);
|
||||
else
|
||||
throw new IllegalArgumentException(networkId.name());
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@ package de.schildbach.oeffi.network;
|
|||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
|
|
@ -24,11 +24,12 @@ import android.widget.ImageButton;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.oeffi.network.NetworkResources;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class NetworkViewHolder extends RecyclerView.ViewHolder {
|
||||
private final Context context;
|
||||
private final Resources res;
|
||||
|
|
|
@ -17,26 +17,27 @@
|
|||
|
||||
package de.schildbach.oeffi.plans;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.SearchManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Process;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ViewAnimator;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.activity.SystemBarStyle;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
@ -68,6 +69,7 @@ import okhttp3.HttpUrl;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.HttpURLConnection;
|
||||
|
@ -79,10 +81,13 @@ import java.util.TreeSet;
|
|||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public class PlanActivity extends Activity {
|
||||
public class PlanActivity extends ComponentActivity {
|
||||
public static final String INTENT_EXTRA_PLAN_ID = "plan_id"; // Used in launcher shortcuts
|
||||
private static final String INTENT_EXTRA_SELECTED_STATION_ID = PlanActivity.class.getName()
|
||||
+ ".selected_station_id";
|
||||
// plan backgrounds are always white, so force navigation bar to light mode
|
||||
private static final SystemBarStyle NAVIGATION_BAR_STYLE = SystemBarStyle.light(Color.TRANSPARENT,
|
||||
Color.TRANSPARENT);
|
||||
|
||||
public static Intent intent(final Context context, final String planId, final String selectedStationId) {
|
||||
final Intent intent = new Intent(Intent.ACTION_VIEW, null, context, PlanActivity.class);
|
||||
|
@ -117,6 +122,7 @@ public class PlanActivity extends Activity {
|
|||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this, Constants.STATUS_BAR_STYLE, NAVIGATION_BAR_STYLE);
|
||||
super.onCreate(savedInstanceState);
|
||||
this.application = (Application) getApplication();
|
||||
|
||||
|
@ -126,7 +132,6 @@ public class PlanActivity extends Activity {
|
|||
backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
|
||||
setContentView(R.layout.plans_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
|
||||
final Animation zoomControlsAnimation = AnimationUtils.loadAnimation(this, R.anim.zoom_controls);
|
||||
zoomControlsAnimation.setFillAfter(true); // workaround: set through code because XML does not work
|
||||
|
@ -255,11 +260,6 @@ public class PlanActivity extends Activity {
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSearchRequested() {
|
||||
if (!stations.isEmpty())
|
||||
|
|
|
@ -25,7 +25,6 @@ import android.database.CursorWrapper;
|
|||
import android.database.MatrixCursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.BaseColumns;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
|
@ -42,6 +41,7 @@ import okhttp3.HttpUrl;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
|
|
|
@ -33,12 +33,15 @@ import android.net.Uri;
|
|||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
|
@ -63,11 +66,12 @@ import okhttp3.HttpUrl;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.net.HttpURLConnection;
|
||||
|
||||
public class PlansPickerActivity extends OeffiMainActivity implements ActivityCompat.OnRequestPermissionsResultCallback,
|
||||
LocationHelper.Callback, PlanClickListener, PlanContextMenuItemListener {
|
||||
public class PlansPickerActivity extends OeffiMainActivity implements LocationHelper.Callback, PlanClickListener,
|
||||
PlanContextMenuItemListener {
|
||||
private ConnectivityManager connectivityManager;
|
||||
private LocationHelper locationHelper;
|
||||
|
||||
|
@ -84,11 +88,15 @@ public class PlansPickerActivity extends OeffiMainActivity implements ActivityCo
|
|||
|
||||
private Cursor cursor;
|
||||
|
||||
private static final int REQUEST_CODE_REQUEST_LOCATION_PERMISSION = 1;
|
||||
private static final int THUMB_CACHE_SIZE = 2 * 1024 * 1024;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PlansPickerActivity.class);
|
||||
|
||||
private final ActivityResultLauncher<String> requestPermissionLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
|
||||
maybeStartLocation();
|
||||
});
|
||||
|
||||
@Override
|
||||
protected String taskName() {
|
||||
return "plans";
|
||||
|
@ -105,10 +113,11 @@ public class PlansPickerActivity extends OeffiMainActivity implements ActivityCo
|
|||
thumbCache = new Cache(cacheDir, THUMB_CACHE_SIZE);
|
||||
|
||||
setContentView(R.layout.plans_picker_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
actionBar = getMyActionBar();
|
||||
|
@ -126,10 +135,10 @@ public class PlansPickerActivity extends OeffiMainActivity implements ActivityCo
|
|||
listView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
|
||||
listAdapter = new PlansAdapter(this, cursor, thumbCache, this, this, application.okHttpClient());
|
||||
listView.setAdapter(listAdapter);
|
||||
listView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(),
|
||||
insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(listView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
connectivityWarningView = findViewById(R.id.plans_picker_connectivity_warning_box);
|
||||
|
@ -154,8 +163,7 @@ public class PlansPickerActivity extends OeffiMainActivity implements ActivityCo
|
|||
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
|
||||
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION },
|
||||
REQUEST_CODE_REQUEST_LOCATION_PERMISSION);
|
||||
requestPermissionLauncher.launch(Manifest.permission.ACCESS_COARSE_LOCATION);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -186,13 +194,6 @@ public class PlansPickerActivity extends OeffiMainActivity implements ActivityCo
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
|
||||
final int[] grantResults) {
|
||||
if (requestCode == REQUEST_CODE_REQUEST_LOCATION_PERMISSION)
|
||||
maybeStartLocation();
|
||||
}
|
||||
|
||||
public void maybeStartLocation() {
|
||||
if (ContextCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
|
||||
|
|
|
@ -29,12 +29,12 @@ import android.widget.ImageView;
|
|||
import android.widget.PopupMenu;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.oeffi.network.NetworkResources;
|
||||
import okhttp3.Call;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
|
||||
public class PlanViewHolder extends RecyclerView.ViewHolder {
|
||||
|
|
|
@ -26,7 +26,6 @@ import android.os.Handler;
|
|||
import android.provider.BaseColumns;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.schildbach.oeffi.Constants;
|
||||
import de.schildbach.oeffi.R;
|
||||
|
@ -39,6 +38,7 @@ import okhttp3.OkHttpClient;
|
|||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
|
|
@ -24,11 +24,12 @@ import android.os.Build;
|
|||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import androidx.annotation.Nullable;
|
||||
import de.schildbach.oeffi.Application;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.oeffi.util.Installer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class AboutFragment extends PreferenceFragment {
|
||||
private static final String KEY_ABOUT_VERSION = "about_version";
|
||||
private static final String KEY_ABOUT_MARKET_APP = "about_market_app";
|
||||
|
|
|
@ -17,20 +17,18 @@
|
|||
|
||||
package de.schildbach.oeffi.preference;
|
||||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceFragment;
|
||||
import androidx.annotation.Nullable;
|
||||
import de.schildbach.oeffi.R;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class CommonFragment extends PreferenceFragment {
|
||||
private static final String KEY_BATTERY_OPTIMIZATIONS = "battery_optimizations";
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
addPreferencesFromResource(R.xml.preference_common);
|
||||
findPreference(KEY_BATTERY_OPTIMIZATIONS).setEnabled(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,10 @@ package de.schildbach.oeffi.preference;
|
|||
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceFragment;
|
||||
import androidx.annotation.Nullable;
|
||||
import de.schildbach.oeffi.R;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DirectionsFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
|
|
|
@ -17,12 +17,13 @@
|
|||
|
||||
package de.schildbach.oeffi.preference;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.os.Bundle;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import androidx.annotation.Nullable;
|
||||
import de.schildbach.oeffi.Constants;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.wallet.integration.android.BitcoinIntegration;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class DonateFragment extends PreferenceFragment {
|
||||
private static final String KEY_ABOUT_DONATE_BITCOIN = "about_donate_bitcoin";
|
||||
|
@ -30,10 +31,14 @@ public class DonateFragment extends PreferenceFragment {
|
|||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
addPreferencesFromResource(R.xml.preference_donate);
|
||||
findPreference(KEY_ABOUT_DONATE_BITCOIN).setOnPreferenceClickListener(preference -> {
|
||||
BitcoinIntegration.request(getActivity(), Constants.BITCOIN_ADDRESS);
|
||||
final Preference donateBitcoinPreference = findPreference(KEY_ABOUT_DONATE_BITCOIN);
|
||||
donateBitcoinPreference.setOnPreferenceClickListener(preference -> {
|
||||
try {
|
||||
startActivity(donateBitcoinPreference.getIntent());
|
||||
} catch (final ActivityNotFoundException x) {
|
||||
donateBitcoinPreference.setEnabled(false);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -19,9 +19,13 @@ package de.schildbach.oeffi.preference;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.oeffi.Variants;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -36,11 +40,21 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
|
|||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(v.getPaddingLeft(), insets.top, v.getPaddingRight(), v.getPaddingBottom());
|
||||
return windowInsets;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBuildHeaders(final List<Header> target) {
|
||||
loadHeadersFromResource(R.xml.preference_headers, target);
|
||||
if (Variants.ENABLE_DONATE)
|
||||
loadHeadersFromResource(R.xml.preference_headers_donate, target);
|
||||
loadHeadersFromResource(R.xml.preference_headers_donate, target);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -59,6 +73,6 @@ public class PreferenceActivity extends android.preference.PreferenceActivity {
|
|||
return CommonFragment.class.getName().equals(fragmentName)
|
||||
|| DirectionsFragment.class.getName().equals(fragmentName)
|
||||
|| AboutFragment.class.getName().equals(fragmentName)
|
||||
|| (Variants.ENABLE_DONATE && DonateFragment.class.getName().equals(fragmentName));
|
||||
|| DonateFragment.class.getName().equals(fragmentName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,125 +0,0 @@
|
|||
/*
|
||||
* Copyright the original author or authors.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.schildbach.oeffi.stations;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import de.schildbach.oeffi.Application;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.oeffi.util.DialogBuilder;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
import de.schildbach.pte.dto.LocationType;
|
||||
import okhttp3.Call;
|
||||
import okhttp3.Callback;
|
||||
import okhttp3.HttpUrl;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DecodeForeignActivity extends Activity {
|
||||
private static final Pattern PATTERN_META_REFRESH = Pattern
|
||||
.compile("<meta\\s+http-equiv=\"refresh\"\\s+content=\"0;\\s+URL=([^\"]*)\"");
|
||||
|
||||
private Application application;
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
this.application = (Application) getApplication();
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final Uri uri = intent.getData();
|
||||
|
||||
if (uri != null && uri.getScheme().equals("http")) {
|
||||
final String host = uri.getHost();
|
||||
final String path = uri.getPath().trim();
|
||||
|
||||
if ("www.rmv.de".equals(host)) {
|
||||
final Matcher m = Pattern.compile("/t/d(\\d+)").matcher(path);
|
||||
if (m.matches()) {
|
||||
final ProgressDialog progressDialog = ProgressDialog.show(DecodeForeignActivity.this, null,
|
||||
getString(R.string.stations_decode_foreign_progress), true, true, dialog -> finish());
|
||||
progressDialog.setCanceledOnTouchOutside(false);
|
||||
|
||||
final Request.Builder request = new Request.Builder();
|
||||
request.url(HttpUrl.parse(uri.toString()));
|
||||
final Call call = application.okHttpClient().newCall(request.build());
|
||||
call.enqueue(new Callback() {
|
||||
public void onResponse(final Call call, final Response r) throws IOException {
|
||||
try (final Response response = r) {
|
||||
if (response.isSuccessful()) {
|
||||
final Matcher mRefresh = PATTERN_META_REFRESH.matcher(response.body().string());
|
||||
if (mRefresh.find()) {
|
||||
final Uri refreshUri = Uri.parse(mRefresh.group(1));
|
||||
|
||||
runOnUiThread(() -> {
|
||||
progressDialog.dismiss();
|
||||
if ("mobil.rmv.de".equals(refreshUri.getHost())
|
||||
&& "/mobile".equals(refreshUri.getPath())) {
|
||||
final String id = refreshUri.getQueryParameter("id");
|
||||
StationDetailsActivity.start(DecodeForeignActivity.this,
|
||||
NetworkId.NVV, new Location(LocationType.STATION, id));
|
||||
finish();
|
||||
} else {
|
||||
errorDialog(R.string.stations_decode_foreign_failed);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
onFail();
|
||||
}
|
||||
} else {
|
||||
onFail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onFailure(final Call call, final IOException x) {
|
||||
onFail();
|
||||
}
|
||||
|
||||
private void onFail() {
|
||||
runOnUiThread(() -> {
|
||||
progressDialog.dismiss();
|
||||
errorDialog(R.string.stations_decode_foreign_failed);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new IllegalArgumentException("cannot handle path: '" + path + "'");
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("cannot handle host: '" + host + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void errorDialog(final int resId) {
|
||||
final DialogBuilder builder = DialogBuilder.warn(this, 0);
|
||||
builder.setMessage(resId);
|
||||
builder.setPositiveButton("Ok", (dialog, which) -> finish());
|
||||
builder.setOnCancelListener(dialog -> finish());
|
||||
builder.show();
|
||||
}
|
||||
}
|
|
@ -24,7 +24,10 @@ import android.net.Uri;
|
|||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.widget.ViewAnimator;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.activity.result.contract.ActivityResultContract;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.schildbach.oeffi.MyActionBar;
|
||||
|
@ -38,6 +41,7 @@ import de.schildbach.pte.NetworkId;
|
|||
import de.schildbach.pte.dto.Departure;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
@ -51,10 +55,21 @@ public class FavoriteStationsActivity extends OeffiActivity
|
|||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void startForResult(final Activity activity, final int requestCode, final NetworkId network) {
|
||||
final Intent intent = new Intent(activity, FavoriteStationsActivity.class);
|
||||
intent.putExtra(INTENT_EXTRA_NETWORK, checkNotNull(network));
|
||||
activity.startActivityForResult(intent, requestCode);
|
||||
public static class PickFavoriteStation extends ActivityResultContract<NetworkId, Uri> {
|
||||
@Override
|
||||
public Intent createIntent(final Context context, final NetworkId network) {
|
||||
final Intent intent = new Intent(context, FavoriteStationsActivity.class);
|
||||
intent.putExtra(INTENT_EXTRA_NETWORK, checkNotNull(network));
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Uri parseResult(final int resultCode, @Nullable final Intent intent) {
|
||||
if (resultCode == Activity.RESULT_OK && intent != null)
|
||||
return intent.getData();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -72,10 +87,11 @@ public class FavoriteStationsActivity extends OeffiActivity
|
|||
network = (NetworkId) intent.getSerializableExtra(INTENT_EXTRA_NETWORK);
|
||||
|
||||
setContentView(R.layout.favorites_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
final MyActionBar actionBar = getMyActionBar();
|
||||
|
@ -90,10 +106,10 @@ public class FavoriteStationsActivity extends OeffiActivity
|
|||
listView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
|
||||
adapter = new FavoriteStationsAdapter(this, network, this, network == null ? this : null);
|
||||
listView.setAdapter(adapter);
|
||||
listView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(),
|
||||
insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(listView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
updateGUI();
|
||||
|
@ -121,6 +137,7 @@ public class FavoriteStationsActivity extends OeffiActivity
|
|||
} else if (menuItemId == R.id.station_context_remove_favorite) {
|
||||
adapter.removeEntry(adapterPosition);
|
||||
updateGUI();
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
@ -17,23 +17,23 @@
|
|||
|
||||
package de.schildbach.oeffi.stations;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
import de.schildbach.pte.dto.LocationType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
|
||||
public class FavoriteUtils {
|
||||
public static Uri persist(final ContentResolver contentResolver, final int type, final NetworkId networkId,
|
||||
final Location station) {
|
||||
checkArgument(station.type == LocationType.STATION, "not a station: %s", station);
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(FavoriteStationsProvider.KEY_TYPE, type);
|
||||
values.put(FavoriteStationsProvider.KEY_STATION_NETWORK, networkId.name());
|
||||
|
@ -71,17 +71,4 @@ public class FavoriteUtils {
|
|||
return favorites;
|
||||
}
|
||||
|
||||
public static void notifyFavoritesChanged(final Context context) {
|
||||
// notify widgets
|
||||
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
|
||||
for (final AppWidgetProviderInfo providerInfo : appWidgetManager.getInstalledProviders()) {
|
||||
// limit to own widgets
|
||||
if (providerInfo.provider.getPackageName().equals(context.getPackageName())) {
|
||||
final Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,
|
||||
appWidgetManager.getAppWidgetIds(providerInfo.provider));
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.graphics.Paint.FontMetrics;
|
|||
import android.graphics.RectF;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.Typeface;
|
||||
import android.os.Build;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.style.ReplacementSpan;
|
||||
|
@ -36,7 +37,6 @@ import android.widget.TextView;
|
|||
import com.google.common.base.Joiner;
|
||||
import com.google.common.base.Strings;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.oeffi.util.CheatSheet;
|
||||
import de.schildbach.pte.Standard;
|
||||
import de.schildbach.pte.dto.Line;
|
||||
import de.schildbach.pte.dto.Line.Attr;
|
||||
|
@ -177,16 +177,19 @@ public class LineView extends TextView {
|
|||
"product_" + Character.toLowerCase(line.productCode()), "string", context.getPackageName());
|
||||
final String sheet = Joiner.on('\n').skipNulls().join(line.name,
|
||||
productResId != 0 ? context.getString(productResId) : null, line.network);
|
||||
if (Strings.emptyToNull(sheet) != null)
|
||||
CheatSheet.setup(this, sheet);
|
||||
else
|
||||
CheatSheet.remove(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
if (Strings.emptyToNull(sheet) != null)
|
||||
setTooltipText(sheet);
|
||||
else
|
||||
setTooltipText(null);
|
||||
} else {
|
||||
CheatSheet.remove(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
setTooltipText(null);
|
||||
}
|
||||
} else {
|
||||
setText(null);
|
||||
CheatSheet.remove(this);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
setTooltipText(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,14 +17,20 @@
|
|||
|
||||
package de.schildbach.oeffi.stations;
|
||||
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetProvider;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class NearestFavoriteStationWidgetProvider extends AppWidgetProvider {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NearestFavoriteStationWidgetProvider.class);
|
||||
|
||||
@Override
|
||||
public void onUpdate(final Context context, final AppWidgetManager appWidgetManager, final int[] appWidgetIds) {
|
||||
NearestFavoriteStationWidgetService.enqueueWork(context, new Intent());
|
||||
public void onReceive(final Context context, final Intent intent) {
|
||||
final String action = intent.getAction();
|
||||
log.info("got broadcast: {}", action);
|
||||
NearestFavoriteStationWidgetService.schedulePeriodic(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ package de.schildbach.oeffi.stations;
|
|||
|
||||
import android.Manifest;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.job.JobInfo;
|
||||
import android.app.job.JobParameters;
|
||||
import android.app.job.JobScheduler;
|
||||
import android.app.job.JobService;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
|
@ -38,10 +42,10 @@ import android.os.Handler;
|
|||
import android.os.HandlerThread;
|
||||
import android.os.Process;
|
||||
import android.text.format.DateFormat;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
import androidx.core.app.JobIntentService;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
|
@ -68,24 +72,59 @@ import java.util.Collections;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
public class NearestFavoriteStationWidgetService extends JobIntentService {
|
||||
public class NearestFavoriteStationWidgetService extends JobService {
|
||||
private AppWidgetManager appWidgetManager;
|
||||
private LocationManager locationManager;
|
||||
private ContentResolver contentResolver;
|
||||
private Executor executor = Executors.newFixedThreadPool(2);
|
||||
private HandlerThread backgroundThread;
|
||||
private Handler backgroundHandler;
|
||||
|
||||
private static final int JOB_ID = 1;
|
||||
public static final String NOTIFICATION_CHANNEL_ID_APPWIDGET = "appwidget";
|
||||
private static final int NOTIFICATION_ID_APPWIDGET_UPDATE = 1;
|
||||
private static final int JOB_ID_PERIODIC = 0;
|
||||
private static final int JOB_ID_IMMEDIATE = 1;
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(NearestFavoriteStationWidgetService.class);
|
||||
|
||||
public static void enqueueWork(final Context context, final Intent work) {
|
||||
enqueueWork(context, NearestFavoriteStationWidgetService.class, JOB_ID, work);
|
||||
public static void schedulePeriodic(final Context context) {
|
||||
final JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
final ComponentName providerName = new ComponentName(context, NearestFavoriteStationWidgetProvider.class);
|
||||
final boolean haveWidgets = AppWidgetManager.getInstance(context).getAppWidgetIds(providerName).length > 0;
|
||||
if (haveWidgets) {
|
||||
final JobInfo.Builder jobInfo = new JobInfo.Builder(JOB_ID_PERIODIC, new ComponentName(context,
|
||||
NearestFavoriteStationWidgetService.class));
|
||||
jobInfo.setPeriodic(DateUtils.MINUTE_IN_MILLIS * 15);
|
||||
jobInfo.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
final JobInfo job = jobInfo.build();
|
||||
jobScheduler.schedule(job);
|
||||
log.info("Scheduled periodic job: {}", job);
|
||||
} else {
|
||||
jobScheduler.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
public static void scheduleImmediate(final Context context) {
|
||||
final JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
|
||||
final ComponentName providerName = new ComponentName(context, NearestFavoriteStationWidgetProvider.class);
|
||||
final boolean haveWidgets = AppWidgetManager.getInstance(context).getAppWidgetIds(providerName).length > 0;
|
||||
if (haveWidgets) {
|
||||
final JobInfo.Builder jobInfo = new JobInfo.Builder(JOB_ID_IMMEDIATE, new ComponentName(context,
|
||||
NearestFavoriteStationWidgetService.class));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
|
||||
jobInfo.setExpedited(true);
|
||||
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P)
|
||||
jobInfo.setImportantWhileForeground(true);
|
||||
jobInfo.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
final JobInfo job = jobInfo.build();
|
||||
jobScheduler.schedule(job);
|
||||
log.info("Scheduled immediate job: {}", job);
|
||||
} else {
|
||||
jobScheduler.cancelAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -110,32 +149,35 @@ public class NearestFavoriteStationWidgetService extends JobIntentService {
|
|||
private RemoteViews views;
|
||||
|
||||
@Override
|
||||
protected void onHandleWork(final Intent intent) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
final NotificationCompat.Builder notification = new NotificationCompat.Builder(this,
|
||||
NOTIFICATION_CHANNEL_ID_APPWIDGET);
|
||||
notification.setSmallIcon(R.drawable.ic_stat_notify_sync_24dp);
|
||||
notification.setWhen(System.currentTimeMillis());
|
||||
notification.setOngoing(true);
|
||||
startForeground(NOTIFICATION_ID_APPWIDGET_UPDATE, notification.build());
|
||||
}
|
||||
|
||||
handleIntent();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
stopForeground(true);
|
||||
public boolean onStartJob(final JobParameters params) {
|
||||
log.info("Job started: {}", params);
|
||||
executor.execute(() -> {
|
||||
runJob();
|
||||
jobFinished(params, false);
|
||||
log.info("Job finished: {}", params);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
private void handleIntent() {
|
||||
@Override
|
||||
public boolean onStopJob(final JobParameters params) {
|
||||
log.info("Job stopped: {}", params);
|
||||
return false;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private void runJob() {
|
||||
final ComponentName providerName = new ComponentName(this, NearestFavoriteStationWidgetProvider.class);
|
||||
final int[] appWidgetIds = appWidgetManager.getAppWidgetIds(providerName);
|
||||
if (appWidgetIds.length == 0)
|
||||
return;
|
||||
|
||||
views = new RemoteViews(getPackageName(), R.layout.station_widget_content);
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED ||
|
||||
(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)) {
|
||||
final PendingIntent intent = PendingIntent.getActivity(this, 0, new Intent(this,
|
||||
NearestFavoriteStationsWidgetPermissionActivity.class), 0);
|
||||
NearestFavoriteStationsWidgetPermissionActivity.class), PendingIntent.FLAG_IMMUTABLE);
|
||||
widgetsMessage(appWidgetIds, getString(R.string.nearest_favorite_station_widget_no_location_permission), intent);
|
||||
log.info("No location permission");
|
||||
return;
|
||||
|
@ -381,7 +423,7 @@ public class NearestFavoriteStationWidgetService extends JobIntentService {
|
|||
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
|
||||
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] { appWidgetId });
|
||||
intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
|
||||
return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
return PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
|
||||
}
|
||||
|
||||
private static class Favorite implements Comparable<Favorite> {
|
||||
|
|
|
@ -18,22 +18,41 @@
|
|||
package de.schildbach.oeffi.stations;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.activity.ComponentActivity;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class NearestFavoriteStationsWidgetPermissionActivity extends ComponentActivity {
|
||||
private static final Logger log = LoggerFactory.getLogger(NearestFavoriteStationsWidgetPermissionActivity.class);
|
||||
|
||||
private final ActivityResultLauncher<String[]> requestPermissionsLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), results -> {
|
||||
for (Map.Entry<String, Boolean> entry : results.entrySet())
|
||||
log.info("{} {}", entry.getKey(), entry.getValue() ? "granted" : "denied");
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
finish();
|
||||
});
|
||||
|
||||
public class NearestFavoriteStationsWidgetPermissionActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
Manifest.permission.ACCESS_BACKGROUND_LOCATION }, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
|
||||
final int[] grantResults) {
|
||||
FavoriteUtils.notifyFavoritesChanged(this);
|
||||
finish();
|
||||
final List<String> permissions = new LinkedList<>();
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
|
||||
permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED)
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || permissions.isEmpty())
|
||||
permissions.add(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
|
||||
log.info("Requesting permissions: {}", permissions);
|
||||
requestPermissionsLauncher.launch(permissions.toArray(new String[0]));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package de.schildbach.oeffi.stations;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import de.schildbach.pte.dto.Departure;
|
||||
import de.schildbach.pte.dto.LineDestination;
|
||||
|
@ -25,6 +24,7 @@ import de.schildbach.pte.dto.Location;
|
|||
import de.schildbach.pte.dto.Product;
|
||||
import de.schildbach.pte.dto.QueryDeparturesResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.content.ComponentName;
|
|||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -121,54 +120,23 @@ public class StationContextMenu extends PopupMenu {
|
|||
public static void prepareMapMenu(final Context context, final Menu menu, final NetworkId network,
|
||||
final Location location) {
|
||||
new MenuInflater(context).inflate(R.menu.station_map_context, menu);
|
||||
final MenuItem googleMapsItem = menu.findItem(R.id.station_map_context_google_maps);
|
||||
final MenuItem amazonMapsItem = menu.findItem(R.id.station_map_context_amazon_maps);
|
||||
final MenuItem openStreetMapItem = menu.findItem(R.id.station_map_context_openstreetmap);
|
||||
final MenuItem googleStreetViewItem = menu.findItem(R.id.station_map_context_google_street_view);
|
||||
final MenuItem googleNavigationItem = menu.findItem(R.id.station_map_context_google_navigation);
|
||||
final MenuItem mapsItem = menu.findItem(R.id.station_map_context_maps);
|
||||
|
||||
if (location.hasCoord()) {
|
||||
final double lat = location.getLatAsDouble();
|
||||
final double lon = location.getLonAsDouble();
|
||||
final String name = location.name;
|
||||
|
||||
final Intent googleMapsIntent = new Intent(Intent.ACTION_VIEW,
|
||||
final Intent mapsIntent = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(String.format(Locale.ENGLISH, "geo:%.6f,%.6f?q=%.6f,%.6f%s", lat, lon, lat, lon,
|
||||
name != null ? '(' + URLEncoder.encode(name.replaceAll("[()]", "")) + ')' : "")));
|
||||
googleMapsIntent.setComponent(
|
||||
new ComponentName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity"));
|
||||
prepareMapMenuItem(context, googleMapsItem, googleMapsIntent);
|
||||
|
||||
final Intent amazonMapsIntent = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(String.format(Locale.ENGLISH, "geo:%.6f,%.6f?q=%.6f,%.6f%s", lat, lon, lat, lon,
|
||||
name != null ? '(' + URLEncoder.encode(name.replaceAll("[()]", "")) + ')' : "")));
|
||||
amazonMapsIntent.setComponent(new ComponentName("com.amazon.geo.client.maps",
|
||||
"com.amazon.geo.client.renderer.MapsAppActivityDuke"));
|
||||
prepareMapMenuItem(context, amazonMapsItem, amazonMapsIntent);
|
||||
|
||||
final Intent openStreetMapIntent = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(String.format(Locale.ENGLISH, "osmand.geo:%.6f,%.6f?q=%.6f,%.6f%s", lat, lon, lat, lon,
|
||||
name != null ? '(' + URLEncoder.encode(name.replaceAll("[()]", "")) + ')' : "")));
|
||||
prepareMapMenuItem(context, openStreetMapItem, openStreetMapIntent);
|
||||
|
||||
final Intent googleStreetViewIntent = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(String.format(Locale.ENGLISH, "google.streetview:cbll=%.6f,%.6f", lat, lon)));
|
||||
googleStreetViewIntent
|
||||
.setComponent(new ComponentName("com.google.android.street", "com.google.android.street.Street"));
|
||||
prepareMapMenuItem(context, googleStreetViewItem, googleStreetViewIntent);
|
||||
|
||||
final Intent googleNavigationIntent = new Intent(Intent.ACTION_VIEW,
|
||||
Uri.parse(String.format(Locale.ENGLISH, "google.navigation:ll=%.6f,%.6f&title=%s&mode=w", lat, lon,
|
||||
name != null ? URLEncoder.encode(name) : "")));
|
||||
googleNavigationIntent.setComponent(new ComponentName("com.google.android.apps.maps",
|
||||
"com.google.android.maps.driveabout.app.NavigationActivity"));
|
||||
prepareMapMenuItem(context, googleNavigationItem, googleNavigationIntent);
|
||||
mapsItem.setOnMenuItemClickListener(item -> {
|
||||
context.startActivity(mapsIntent);
|
||||
return true;
|
||||
});
|
||||
mapsItem.setVisible(true);
|
||||
} else {
|
||||
googleMapsItem.setVisible(false);
|
||||
amazonMapsItem.setVisible(false);
|
||||
openStreetMapItem.setVisible(false);
|
||||
googleStreetViewItem.setVisible(false);
|
||||
googleNavigationItem.setVisible(false);
|
||||
mapsItem.setVisible(false);
|
||||
}
|
||||
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
|
@ -192,13 +160,4 @@ public class StationContextMenu extends PopupMenu {
|
|||
stationsCursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static void prepareMapMenuItem(final Context context, final MenuItem item, final Intent intent) {
|
||||
final PackageManager pm = context.getPackageManager();
|
||||
item.setVisible(pm.resolveActivity(intent, 0) != null);
|
||||
item.setOnMenuItemClickListener(item1 -> {
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,11 +34,12 @@ import android.text.format.DateUtils;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ViewAnimator;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.common.base.Joiner;
|
||||
|
@ -59,22 +60,23 @@ import de.schildbach.pte.dto.Line;
|
|||
import de.schildbach.pte.dto.LineDestination;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
import de.schildbach.pte.dto.LocationType;
|
||||
import de.schildbach.pte.dto.Product;
|
||||
import de.schildbach.pte.dto.QueryDeparturesResult;
|
||||
import de.schildbach.pte.dto.StationDepartures;
|
||||
import org.osmdroid.util.GeoPoint;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
@ -138,10 +140,11 @@ public class StationDetailsActivity extends OeffiActivity implements StationsAwa
|
|||
backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
|
||||
setContentView(R.layout.stations_station_details_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
actionBar = getMyActionBar();
|
||||
|
@ -157,13 +160,13 @@ public class StationDetailsActivity extends OeffiActivity implements StationsAwa
|
|||
FavoriteStationsProvider.TYPE_FAVORITE, selectedNetwork, selectedStation);
|
||||
if (rowUri != null) {
|
||||
selectedFavState = FavoriteStationsProvider.TYPE_FAVORITE;
|
||||
FavoriteUtils.notifyFavoritesChanged(StationDetailsActivity.this);
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
}
|
||||
} else {
|
||||
final int numRows = FavoriteUtils.delete(getContentResolver(), selectedNetwork, selectedStation.id);
|
||||
if (numRows > 0) {
|
||||
selectedFavState = null;
|
||||
FavoriteUtils.notifyFavoritesChanged(StationDetailsActivity.this);
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -175,111 +178,41 @@ public class StationDetailsActivity extends OeffiActivity implements StationsAwa
|
|||
listView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
|
||||
listAdapter = new DeparturesAdapter(this);
|
||||
listView.setAdapter(listAdapter);
|
||||
listView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(listView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(),
|
||||
insets.getSystemWindowInsetBottom() + (int)(48 * getResources().getDisplayMetrics().density));
|
||||
return insets;
|
||||
insets.bottom + (int) (48 * getResources().getDisplayMetrics().density));
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
mapView = findViewById(R.id.stations_station_details_map);
|
||||
mapView.setStationsAware(this);
|
||||
final TextView mapDisclaimerView = findViewById(R.id.stations_station_details_map_disclaimer);
|
||||
mapDisclaimerView.setText(mapView.getTileProvider().getTileSource().getCopyrightNotice());
|
||||
mapDisclaimerView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0,0,0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mapDisclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
resultStatusView = findViewById(R.id.stations_station_details_result_status);
|
||||
|
||||
final Intent intent = getIntent();
|
||||
final Uri uri = intent.getData();
|
||||
|
||||
if (uri != null && uri.getScheme().equals("http")) {
|
||||
log.info("Got intent: {}", intent);
|
||||
|
||||
final String host = uri.getHost();
|
||||
final String path = uri.getPath().trim();
|
||||
|
||||
if ("oeffi.schildbach.de".equals(host)) {
|
||||
final NetworkId network = NetworkId.valueOf(uri.getQueryParameter("network").toUpperCase());
|
||||
final String stationId = uri.getQueryParameter("id");
|
||||
selectStation(new Station(network, new Location(LocationType.STATION, stationId, null, null)));
|
||||
} else if ("qr.bvg.de".equals(host)) {
|
||||
final Matcher m = Pattern.compile("/h(\\d+)").matcher(path);
|
||||
if (m.matches()) {
|
||||
final NetworkId network = NetworkId.BVG;
|
||||
String stationId = bvgStationIdNfcToQr(m.group(1));
|
||||
if (stationId.length() <= 6) // mast
|
||||
stationId = '~' + stationId;
|
||||
selectStation(new Station(network, new Location(LocationType.STATION, stationId, null, null)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("could not parse path: '" + path + "'");
|
||||
}
|
||||
} else if ("mobil.s-bahn-berlin.de".equals(host)) {
|
||||
if ("/".equals(path)) {
|
||||
final NetworkId network = NetworkId.VBB;
|
||||
final String qr = uri.getQueryParameter("QR");
|
||||
final String stationId = qr != null ? qr : uri.getQueryParameter("qr");
|
||||
selectStation(new Station(network, new Location(LocationType.STATION, stationId, null, null)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("could not parse path: '" + path + "'");
|
||||
}
|
||||
} else if ("www.mvg-live.de".equals(host)) {
|
||||
final Matcher m = Pattern.compile("/qr/(\\d+)-\\d*-\\d*").matcher(path);
|
||||
if (m.matches()) {
|
||||
final NetworkId network = NetworkId.MVV;
|
||||
final String stationId = m.group(1);
|
||||
selectStation(new Station(network, new Location(LocationType.STATION, stationId, null, null)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("could not parse path: '" + path + "'");
|
||||
}
|
||||
} else if ("wap.rmv.de".equals(host)) {
|
||||
final NetworkId network = NetworkId.NVV;
|
||||
final String stationId = uri.getQueryParameter("id");
|
||||
selectStation(new Station(network, new Location(LocationType.STATION, stationId, null, null)));
|
||||
} else if ("m.vrn.de".equals(host)) {
|
||||
final Matcher m = Pattern.compile("/(\\d+)").matcher(path);
|
||||
if (m.matches()) {
|
||||
final NetworkId network = NetworkId.VRN;
|
||||
final String stationId = Integer.toString(Integer.parseInt(m.group(1)) + 6000000);
|
||||
selectStation(new Station(network, new Location(LocationType.STATION, stationId, null, null)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("could not parse path: '" + path + "'");
|
||||
}
|
||||
} else if ("www.rheinbahn.de".equals(host)) {
|
||||
final Matcher m = Pattern.compile("/QRBarcode/HS/(\\d+)_\\d*.html").matcher(path);
|
||||
if (m.matches()) {
|
||||
final NetworkId network = NetworkId.VRR;
|
||||
final String stationId = Integer.toString(Integer.parseInt(m.group(1)) + 20000000);
|
||||
selectStation(new Station(network, new Location(LocationType.STATION, stationId, null, null)));
|
||||
} else {
|
||||
throw new IllegalArgumentException("could not parse path: '" + path + "'");
|
||||
}
|
||||
} else if ("mobil.vvs.de".equals(host)) {
|
||||
final NetworkId network = NetworkId.VVS;
|
||||
final int stationId = Integer.parseInt(uri.getQueryParameter("name_dm"));
|
||||
// final String lineId = uri.getQueryParameter("line");
|
||||
selectStation(new Station(network, new Location(LocationType.STATION,
|
||||
Integer.toString(stationId < 10000 ? stationId + 5000000 : stationId), null, null)));
|
||||
} else {
|
||||
throw new RuntimeException("cannot handle host: '" + host + "'");
|
||||
}
|
||||
} else {
|
||||
final NetworkId network = (NetworkId) checkNotNull(getIntent().getSerializableExtra(INTENT_EXTRA_NETWORK));
|
||||
final Station station = new Station(network, (Location) intent.getSerializableExtra(INTENT_EXTRA_STATION));
|
||||
if (intent.hasExtra(INTENT_EXTRA_DEPARTURES))
|
||||
station.departures = (List<Departure>) intent.getSerializableExtra(INTENT_EXTRA_DEPARTURES);
|
||||
selectStation(station);
|
||||
statusMessage(getString(R.string.stations_station_details_progress));
|
||||
}
|
||||
final NetworkId network = (NetworkId) checkNotNull(intent.getSerializableExtra(INTENT_EXTRA_NETWORK));
|
||||
final Station station = new Station(network, (Location) intent.getSerializableExtra(INTENT_EXTRA_STATION));
|
||||
if (intent.hasExtra(INTENT_EXTRA_DEPARTURES))
|
||||
station.departures = (List<Departure>) intent.getSerializableExtra(INTENT_EXTRA_DEPARTURES);
|
||||
selectStation(station);
|
||||
statusMessage(getString(R.string.stations_station_details_progress));
|
||||
|
||||
favoriteButton
|
||||
.setChecked(selectedFavState != null && selectedFavState == FavoriteStationsProvider.TYPE_FAVORITE);
|
||||
|
||||
findViewById(R.id.stations_station_details_disclaimer_group).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
final View disclaimerView = findViewById(R.id.stations_station_details_disclaimer_group);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(disclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
disclaimerSourceView = findViewById(R.id.stations_station_details_disclaimer_source);
|
||||
updateDisclaimerSource(disclaimerSourceView, selectedNetwork.name(), null);
|
||||
|
@ -332,11 +265,6 @@ public class StationDetailsActivity extends OeffiActivity implements StationsAwa
|
|||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(final Configuration config) {
|
||||
super.onConfigurationChanged(config);
|
||||
|
@ -505,9 +433,8 @@ public class StationDetailsActivity extends OeffiActivity implements StationsAwa
|
|||
@Override
|
||||
public int getItemCount() {
|
||||
final List<Departure> selectedDepartures = StationDetailsActivity.this.selectedDepartures;
|
||||
if (selectedDepartures == null || selectedDepartures.isEmpty())
|
||||
return 1;
|
||||
return selectedDepartures.size();
|
||||
final int numDepartures = selectedDepartures != null ? selectedDepartures.size() : 0;
|
||||
return numDepartures + 1; // account for header
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -693,9 +620,17 @@ public class StationDetailsActivity extends OeffiActivity implements StationsAwa
|
|||
itemView.setOnClickListener(null);
|
||||
}
|
||||
|
||||
// position
|
||||
positionView.setText(departure.position != null ? Constants.DESTINATION_ARROW_INVISIBLE_PREFIX
|
||||
+ context.getString(R.string.position_platform, departure.position) : null);
|
||||
// position: use german translation "Gleis" only for trains, otherwise use "Steig"
|
||||
boolean isTrain = departure.line.product != null &&
|
||||
EnumSet.of(Product.HIGH_SPEED_TRAIN, Product.REGIONAL_TRAIN, Product.SUBURBAN_TRAIN,
|
||||
Product.SUBWAY).contains(departure.line.product);
|
||||
positionView.setText(departure.position != null ?
|
||||
Constants.DESTINATION_ARROW_INVISIBLE_PREFIX +
|
||||
context.getString(isTrain ?
|
||||
R.string.position_platform_train :
|
||||
R.string.position_platform,
|
||||
departure.position) :
|
||||
null);
|
||||
|
||||
// capacity
|
||||
final int[] capacity = departure.capacity;
|
||||
|
|
|
@ -53,9 +53,12 @@ import android.view.ViewGroup;
|
|||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ViewAnimator;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
@ -99,6 +102,7 @@ import org.osmdroid.util.GeoPoint;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -116,7 +120,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
public class StationsActivity extends OeffiMainActivity implements StationsAware, LocationAware,
|
||||
ActivityCompat.OnRequestPermissionsResultCallback, StationContextMenuItemListener {
|
||||
StationContextMenuItemListener {
|
||||
private ConnectivityManager connectivityManager;
|
||||
private LocationManager locationManager;
|
||||
private SensorManager sensorManager;
|
||||
|
@ -160,6 +164,11 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(StationsActivity.class);
|
||||
|
||||
private final ActivityResultLauncher<String> requestPermissionLauncher =
|
||||
registerForActivityResult(new ActivityResultContracts.RequestPermission(), granted -> {
|
||||
startLocationProvider();
|
||||
});
|
||||
|
||||
@Override
|
||||
protected String taskName() {
|
||||
return "stations";
|
||||
|
@ -178,10 +187,11 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
res = getResources();
|
||||
|
||||
setContentView(R.layout.stations_content);
|
||||
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
||||
findViewById(android.R.id.content).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), 0);
|
||||
return insets;
|
||||
final View contentView = findViewById(android.R.id.content);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(contentView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(insets.left, 0, insets.right, 0);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
actionBar = getMyActionBar();
|
||||
|
@ -244,8 +254,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
|
||||
final Button locationPermissionRequestButton = findViewById(
|
||||
R.id.stations_location_permission_request_button);
|
||||
locationPermissionRequestButton.setOnClickListener(v -> ActivityCompat.requestPermissions(StationsActivity.this,
|
||||
new String[] { Manifest.permission.ACCESS_FINE_LOCATION }, 0));
|
||||
locationPermissionRequestButton.setOnClickListener(v -> requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION));
|
||||
|
||||
final Button locationSettingsButton = findViewById(R.id.stations_list_location_settings);
|
||||
locationSettingsButton.setOnClickListener(v -> startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)));
|
||||
|
@ -261,22 +270,26 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
mapView.setLocationAware(this);
|
||||
final TextView mapDisclaimerView = findViewById(R.id.stations_map_disclaimer);
|
||||
mapDisclaimerView.setText(mapView.getTileProvider().getTileSource().getCopyrightNotice());
|
||||
mapDisclaimerView.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(mapDisclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
|
||||
final ZoomControls zoom = findViewById(R.id.stations_map_zoom);
|
||||
zoom.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
ViewCompat.setOnApplyWindowInsetsListener(zoom, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
mapView.setZoomControls(zoom);
|
||||
|
||||
connectivityWarningView = findViewById(R.id.stations_connectivity_warning_box);
|
||||
findViewById(R.id.stations_disclaimer_group).setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
v.setPadding(0, 0, 0, insets.getSystemWindowInsetBottom());
|
||||
return insets;
|
||||
final View disclaimerView = findViewById(R.id.stations_disclaimer_group);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(disclaimerView, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(0, 0, 0, insets.bottom);
|
||||
return windowInsets;
|
||||
});
|
||||
disclaimerSourceView = findViewById(R.id.stations_disclaimer_source);
|
||||
|
||||
|
@ -410,10 +423,11 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
stationList.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST));
|
||||
stationListAdapter = new StationsAdapter(this, maxDeparturesPerStation, products, this, this);
|
||||
stationList.setAdapter(stationListAdapter);
|
||||
stationList.setOnApplyWindowInsetsListener((v, insets) -> {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(stationList, (v, windowInsets) -> {
|
||||
final Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(),
|
||||
insets.getSystemWindowInsetBottom() + (int)(48 * res.getDisplayMetrics().density));
|
||||
return insets;
|
||||
insets.bottom + (int) (48 * res.getDisplayMetrics().density));
|
||||
return windowInsets;
|
||||
});
|
||||
stationList.addOnScrollListener(new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
|
@ -696,7 +710,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
if (rowUri != null) {
|
||||
favorites.put(location.id, FavoriteStationsProvider.TYPE_FAVORITE);
|
||||
postLoadNextVisible(0);
|
||||
FavoriteUtils.notifyFavoritesChanged(this);
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -707,7 +721,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
final int numRows = FavoriteUtils.delete(getContentResolver(), network, location.id);
|
||||
if (numRows > 0) {
|
||||
favorites.remove(location.id);
|
||||
FavoriteUtils.notifyFavoritesChanged(this);
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -719,7 +733,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
network, location);
|
||||
if (rowUriIgnored != null) {
|
||||
favorites.put(location.id, FavoriteStationsProvider.TYPE_IGNORE);
|
||||
FavoriteUtils.notifyFavoritesChanged(this);
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -731,7 +745,7 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
if (numRowsIgnored > 0) {
|
||||
favorites.remove(location.id);
|
||||
postLoadNextVisible(0);
|
||||
FavoriteUtils.notifyFavoritesChanged(this);
|
||||
NearestFavoriteStationWidgetService.scheduleImmediate(this); // refresh app-widget
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -1342,13 +1356,6 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
|
||||
final int[] grantResults) {
|
||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
|
||||
startLocationProvider();
|
||||
}
|
||||
|
||||
public boolean onStationContextMenuItemClick(final int adapterPosition, final NetworkId network,
|
||||
final Location station, final @Nullable List<Departure> departures, final int menuItemId) {
|
||||
if (menuItemId == R.id.station_context_add_favorite) {
|
||||
|
@ -1498,11 +1505,12 @@ public class StationsActivity extends OeffiMainActivity implements StationsAware
|
|||
try {
|
||||
final SuggestLocationsResult result = networkProvider.suggestLocations(query,
|
||||
EnumSet.of(LocationType.STATION), 0);
|
||||
if (result.status == SuggestLocationsResult.Status.OK)
|
||||
if (result.status == SuggestLocationsResult.Status.OK) {
|
||||
log.info("Got {}", result.toShortString());
|
||||
for (final Location l : result.getLocations())
|
||||
if (l.type == LocationType.STATION)
|
||||
stations.add(new Station(network, l));
|
||||
}
|
||||
} catch (final IOException x) {
|
||||
x.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -24,13 +24,14 @@ import android.net.Uri;
|
|||
import android.provider.BaseColumns;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import de.schildbach.oeffi.R;
|
||||
import de.schildbach.oeffi.stations.FavoriteStationsProvider;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class FavoriteStationsAdapter extends RecyclerView.Adapter<FavoriteStationViewHolder> {
|
||||
private final Context context;
|
||||
private final ContentResolver contentResolver;
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
|
||||
package de.schildbach.oeffi.stations.list;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import de.schildbach.pte.NetworkId;
|
||||
import de.schildbach.pte.dto.Departure;
|
||||
import de.schildbach.pte.dto.Location;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
public interface StationContextMenuItemListener {
|
||||
|
|
|
@ -30,7 +30,6 @@ import android.view.WindowManager;
|
|||
import android.widget.ImageButton;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.common.base.Joiner;
|
||||
import de.schildbach.oeffi.Constants;
|
||||
|
@ -50,6 +49,7 @@ import de.schildbach.pte.dto.Location;
|
|||
import de.schildbach.pte.dto.Product;
|
||||
import de.schildbach.pte.dto.QueryDeparturesResult;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
|
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* Copyright 2012 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package de.schildbach.oeffi.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* Helper class for showing cheat sheets (tooltips) for icon-only UI elements on long-press. This is already
|
||||
* default platform behavior for icon-only {@link android.app.ActionBar} items and tabs. This class provides
|
||||
* this behavior for any other such UI element.
|
||||
*
|
||||
* <p>
|
||||
* Based on the original action bar implementation in <a href=
|
||||
* "https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/com/android/internal/view/menu/ActionMenuItemView.java">
|
||||
* ActionMenuItemView.java</a>.
|
||||
*/
|
||||
public class CheatSheet {
|
||||
/**
|
||||
* The estimated height of a toast, in dips (density-independent pixels). This is used to determine
|
||||
* whether or not the toast should appear above or below the UI element.
|
||||
*/
|
||||
private static final int ESTIMATED_TOAST_HEIGHT_DIPS = 48;
|
||||
|
||||
/**
|
||||
* Sets up a cheat sheet (tooltip) for the given view by setting its
|
||||
* {@link android.view.View.OnLongClickListener}. When the view is long-pressed, a {@link Toast} with the
|
||||
* view's {@link android.view.View#getContentDescription() content description} will be shown either above
|
||||
* (default) or below the view (if there isn't room above it).
|
||||
*
|
||||
* @param view
|
||||
* The view to add a cheat sheet for.
|
||||
*/
|
||||
public static void setup(View view) {
|
||||
view.setOnLongClickListener(v -> showCheatSheet(v, v.getContentDescription()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a cheat sheet (tooltip) for the given view by setting its
|
||||
* {@link android.view.View.OnLongClickListener}. When the view is long-pressed, a {@link Toast} with the
|
||||
* given text will be shown either above (default) or below the view (if there isn't room above it).
|
||||
*
|
||||
* @param view
|
||||
* The view to add a cheat sheet for.
|
||||
* @param textResId
|
||||
* The string resource containing the text to show on long-press.
|
||||
*/
|
||||
public static void setup(View view, final int textResId) {
|
||||
view.setOnLongClickListener(v -> showCheatSheet(v, v.getContext().getString(textResId)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a cheat sheet (tooltip) for the given view by setting its
|
||||
* {@link android.view.View.OnLongClickListener}. When the view is long-pressed, a {@link Toast} with the
|
||||
* given text will be shown either above (default) or below the view (if there isn't room above it).
|
||||
*
|
||||
* @param view
|
||||
* The view to add a cheat sheet for.
|
||||
* @param text
|
||||
* The text to show on long-press.
|
||||
*/
|
||||
public static void setup(View view, final CharSequence text) {
|
||||
view.setOnLongClickListener(v -> showCheatSheet(v, text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cheat sheet for the given view by removing the view's
|
||||
* {@link android.view.View.OnLongClickListener}.
|
||||
*
|
||||
* @param view
|
||||
* The view whose cheat sheet should be removed.
|
||||
*/
|
||||
public static void remove(final View view) {
|
||||
view.setOnLongClickListener(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal helper method to show the cheat sheet toast.
|
||||
*/
|
||||
private static boolean showCheatSheet(View view, CharSequence text) {
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int[] screenPos = new int[2]; // origin is device display
|
||||
final Rect displayFrame = new Rect(); // includes decorations (e.g. status bar)
|
||||
view.getLocationOnScreen(screenPos);
|
||||
view.getWindowVisibleDisplayFrame(displayFrame);
|
||||
|
||||
final Context context = view.getContext();
|
||||
final int viewWidth = view.getWidth();
|
||||
final int viewHeight = view.getHeight();
|
||||
final int viewCenterX = screenPos[0] + viewWidth / 2;
|
||||
final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
|
||||
final int estimatedToastHeight = (int) (ESTIMATED_TOAST_HEIGHT_DIPS
|
||||
* context.getResources().getDisplayMetrics().density);
|
||||
|
||||
Toast cheatSheet = Toast.makeText(context, text, Toast.LENGTH_SHORT);
|
||||
boolean showBelow = screenPos[1] < estimatedToastHeight;
|
||||
if (showBelow) {
|
||||
// Show below
|
||||
// Offsets are after decorations (e.g. status bar) are factored in
|
||||
cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, viewCenterX - screenWidth / 2,
|
||||
screenPos[1] - displayFrame.top + viewHeight);
|
||||
} else {
|
||||
// Show above
|
||||
// Offsets are after decorations (e.g. status bar) are factored in
|
||||
// NOTE: We can't use Gravity.BOTTOM because when the keyboard is up
|
||||
// its height isn't factored in.
|
||||
cheatSheet.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, viewCenterX - screenWidth / 2,
|
||||
screenPos[1] - displayFrame.top - estimatedToastHeight);
|
||||
}
|
||||
|
||||
cheatSheet.show();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package de.schildbach.oeffi.util;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import com.google.common.util.concurrent.Striped;
|
||||
|
@ -33,6 +32,7 @@ import okhttp3.ResponseBody;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
|
|
@ -181,8 +181,7 @@ public class ErrorReporter implements Thread.UncaughtExceptionHandler {
|
|||
report.append("Manufacturer: " + Build.MANUFACTURER + "\n");
|
||||
report.append("Phone Model: " + Build.MODEL + "\n");
|
||||
report.append("Android Version: " + Build.VERSION.RELEASE + "\n");
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||
report.append("Android security patch level: ").append(Build.VERSION.SECURITY_PATCH).append("\n");
|
||||
report.append("Android security patch level: ").append(Build.VERSION.SECURITY_PATCH).append("\n");
|
||||
report.append("ABIs: ").append(Joiner.on(", ").skipNulls().join(Strings.emptyToNull(Build.CPU_ABI),
|
||||
Strings.emptyToNull(Build.CPU_ABI2))).append("\n");
|
||||
report.append("Board: " + Build.BOARD + "\n");
|
||||
|
@ -315,15 +314,12 @@ public class ErrorReporter implements Thread.UncaughtExceptionHandler {
|
|||
|
||||
private final static Pattern PATTERN_VERSION = Pattern.compile("<dt id=\"(\\d+)\">([^<]*)</dt>");
|
||||
|
||||
public void check(final Context context, final int applicationVersionCode, final String applicationVersionFlavor,
|
||||
final OkHttpClient okHttpClient) {
|
||||
public void check(final Context context, final int applicationVersionCode, final OkHttpClient okHttpClient) {
|
||||
if (!stackTraceFile.exists())
|
||||
return;
|
||||
|
||||
final HttpUrl.Builder url = HttpUrl.parse(context.getString(R.string.about_changelog_summary)).newBuilder();
|
||||
url.addQueryParameter("version", Integer.toString(applicationVersionCode));
|
||||
if (applicationVersionFlavor != null)
|
||||
url.addQueryParameter("flavor", applicationVersionFlavor);
|
||||
url.addQueryParameter("sdk", Integer.toString(Build.VERSION.SDK_INT));
|
||||
url.addQueryParameter("check", null);
|
||||
final Request.Builder request = new Request.Builder().url(url.build());
|
||||
|
|
|
@ -42,38 +42,8 @@ public class LocationUriParser {
|
|||
}
|
||||
|
||||
final String scheme = uri.getScheme();
|
||||
final String host = uri.getHost();
|
||||
final String query = uri.getQuery();
|
||||
|
||||
if (("http".equals(scheme) || "https".equals(scheme)) && "maps.google.com".equals(host)) {
|
||||
final String q = getQueryParameter(query, "q");
|
||||
|
||||
final String saddr = getQueryParameter(query, "saddr");
|
||||
final String sll = getQueryParameter(query, "sll");
|
||||
final Location fromLocation;
|
||||
if (saddr != null)
|
||||
fromLocation = parseAddrParam(saddr, null);
|
||||
else if (sll != null)
|
||||
fromLocation = parseAddrParam(sll, q);
|
||||
else if (q != null)
|
||||
fromLocation = new Location(LocationType.ANY, null, null, q);
|
||||
else
|
||||
fromLocation = null;
|
||||
|
||||
final String daddr = getQueryParameter(query, "daddr");
|
||||
if (daddr != null)
|
||||
return new Location[] { fromLocation, parseAddrParam(daddr, null) };
|
||||
else
|
||||
return new Location[] { fromLocation };
|
||||
} else if ("google.navigation".equals(scheme)) {
|
||||
final Location location;
|
||||
if (uri.isOpaque())
|
||||
location = parseGoogleNavigation(uri.getSchemeSpecificPart());
|
||||
else
|
||||
location = parseGoogleNavigation(uri.getQuery());
|
||||
|
||||
return new Location[] { location };
|
||||
} else if ("geo".equals(scheme)) {
|
||||
if ("geo".equals(scheme)) {
|
||||
final Location location = parseGeo(uri.getSchemeSpecificPart().replaceAll(",?\n+", ",+"));
|
||||
|
||||
return new Location[] { location };
|
||||
|
@ -82,25 +52,6 @@ public class LocationUriParser {
|
|||
throw new IllegalArgumentException("cannot parse: '" + encodedUriString + "'");
|
||||
}
|
||||
|
||||
private static Location parseGoogleNavigation(final String query) {
|
||||
final String q = getQueryParameter(query, "q");
|
||||
final String ll = getQueryParameter(query, "ll");
|
||||
final String title = getQueryParameter(query, "title");
|
||||
|
||||
if (ll != null) {
|
||||
return parseAddrParam(ll, title != null ? title : q);
|
||||
} else if (q != null) {
|
||||
final Location location = parseAddrParam(q, title);
|
||||
|
||||
if (location != null)
|
||||
return location;
|
||||
else
|
||||
return new Location(LocationType.ANY, null, null, q);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("cannot parse: '" + query + "'");
|
||||
}
|
||||
|
||||
private static final Pattern P_URI_GEO = Pattern.compile("(-?\\d*\\.?\\d+),(-?\\d*\\.?\\d+)", Pattern.DOTALL);
|
||||
|
||||
private static Location parseGeo(final String query) throws NumberFormatException {
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
package de.schildbach.oeffi.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.widget.TextView;
|
||||
import de.schildbach.oeffi.R;
|
||||
|
||||
public class Toast {
|
||||
private final Context context;
|
||||
|
|
|
@ -23,150 +23,6 @@ import org.junit.Assert;
|
|||
import org.junit.Test;
|
||||
|
||||
public class LocationUriParserTest {
|
||||
@Test
|
||||
public void googleNow() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"http://maps.google.com/maps/?saddr=@53.5878849,9.9050791&daddr=home@52.36894989013672,9.719719886779785&layer=t&dirflg=d");
|
||||
|
||||
Assert.assertEquals(2, results.length);
|
||||
final Location fromLocation = results[0];
|
||||
final Location toLocation = results[1];
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, fromLocation.type);
|
||||
Assert.assertEquals(9905079, fromLocation.getLonAs1E6());
|
||||
Assert.assertEquals(53587885, fromLocation.getLatAs1E6());
|
||||
Assert.assertNull(fromLocation.name);
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, toLocation.type);
|
||||
Assert.assertEquals(9719720, toLocation.getLonAs1E6());
|
||||
Assert.assertEquals(52368950, toLocation.getLatAs1E6());
|
||||
Assert.assertEquals("home", toLocation.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void oldGoogleNow() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"http://maps.google.com/maps?daddr=52.52568054199219,13.374129295349121(Work)&dirflg=r&saddr=52.5360876,13.4263088");
|
||||
|
||||
Assert.assertEquals(2, results.length);
|
||||
final Location fromLocation = results[0];
|
||||
final Location toLocation = results[1];
|
||||
|
||||
Assert.assertEquals(LocationType.COORD, fromLocation.type);
|
||||
Assert.assertEquals(13426309, fromLocation.getLonAs1E6());
|
||||
Assert.assertEquals(52536088, fromLocation.getLatAs1E6());
|
||||
Assert.assertNull(fromLocation.name);
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, toLocation.type);
|
||||
Assert.assertEquals(13374129, toLocation.getLonAs1E6());
|
||||
Assert.assertEquals(52525681, toLocation.getLatAs1E6());
|
||||
Assert.assertEquals("Work", toLocation.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void artem() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"http://maps.google.com/maps?saddr=52.5474,13.344510000000014&daddr=52.5057193,13.353883799999949");
|
||||
|
||||
Assert.assertEquals(2, results.length);
|
||||
final Location fromLocation = results[0];
|
||||
final Location toLocation = results[1];
|
||||
|
||||
Assert.assertEquals(LocationType.COORD, fromLocation.type);
|
||||
Assert.assertEquals(13344510, fromLocation.getLonAs1E6());
|
||||
Assert.assertEquals(52547400, fromLocation.getLatAs1E6());
|
||||
Assert.assertNull(fromLocation.name);
|
||||
|
||||
Assert.assertEquals(LocationType.COORD, toLocation.type);
|
||||
Assert.assertEquals(13353884, toLocation.getLonAs1E6());
|
||||
Assert.assertEquals(52505719, toLocation.getLatAs1E6());
|
||||
Assert.assertNull(toLocation.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleNavigationThrownByGoogleNow() throws Exception {
|
||||
// "Take me to Alexanderplatz"
|
||||
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"google.navigation:title=Alexanderplatz,+10178+Berlin&ll=52.521918,13.413215&token=Fb5rIQMdX6vMACFuFuRmwwH8MA&entry=r&mode=d");
|
||||
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, location.type);
|
||||
Assert.assertEquals(13413215, location.getLonAs1E6());
|
||||
Assert.assertEquals(52521918, location.getLatAs1E6());
|
||||
Assert.assertEquals("Alexanderplatz, 10178 Berlin", location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleNavigation() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"google.navigation:///?ll=52.512845,13.420671&q=Rungestraße+20,+10179+Berlin&title=c-base&entry=w&opt=+flg=0x3000000");
|
||||
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, location.type);
|
||||
Assert.assertEquals(13420671, location.getLonAs1E6());
|
||||
Assert.assertEquals(52512845, location.getLatAs1E6());
|
||||
Assert.assertEquals("c-base", location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleNavigationOpaque() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"google.navigation:q=Work&ll=47.460044860839844,9.6347074508667&mode=d&entry=r&altvia=47.4140989,9.7192978&altvia=47.460046399999996,9.6350649");
|
||||
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, location.type);
|
||||
Assert.assertEquals(9634707, location.getLonAs1E6());
|
||||
Assert.assertEquals(47460045, location.getLatAs1E6());
|
||||
Assert.assertEquals("Work", location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleNavigationQueryOnly() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations("google.navigation:///?q=gleimstr.&mode=w&entry=v");
|
||||
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
|
||||
Assert.assertEquals(LocationType.ANY, location.type);
|
||||
Assert.assertFalse(location.hasCoord());
|
||||
Assert.assertEquals("gleimstr.", location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleNavigationTitle() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"google.navigation:///?ll=52.535836,13.401525&title=Zionskirchstraße+7,+10119+Berlin,+Germany&entry=w");
|
||||
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, location.type);
|
||||
Assert.assertEquals(13401525, location.getLonAs1E6());
|
||||
Assert.assertEquals(52535836, location.getLatAs1E6());
|
||||
Assert.assertEquals("Zionskirchstraße 7, 10119 Berlin, Germany", location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleNavigationQueryOnlyMixed() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"google.navigation:///?q=52.513064,13.420106000000033(C-Base,+Rungestraße,+Berlin,+Germany)&entry=w");
|
||||
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, location.type);
|
||||
Assert.assertEquals(13420106, location.getLonAs1E6());
|
||||
Assert.assertEquals(52513064, location.getLatAs1E6());
|
||||
Assert.assertEquals("C-Base, Rungestraße, Berlin, Germany", location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contacts() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations("geo:0,0?q=Karl-Marx-Allee+84,+Berlin");
|
||||
|
@ -222,22 +78,6 @@ public class LocationUriParserTest {
|
|||
Assert.assertEquals("Prinzenstraße 85, Berlin", location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calendar() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"http://maps.google.com/maps?q=motion*s Tanz- und Bewegungsstudio - Stella Caric GmbH, Prinzenstraße 85, Aufgang B1 - Zugang von der Oranienstraße, 10969 Berlin, Germany&sll=52.50352,13.409187999999972&radius=5");
|
||||
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
|
||||
Assert.assertEquals(LocationType.ADDRESS, location.type);
|
||||
Assert.assertEquals(52503520, location.getLatAs1E6());
|
||||
Assert.assertEquals(13409188, location.getLonAs1E6());
|
||||
Assert.assertEquals(
|
||||
"motion*s Tanz- und Bewegungsstudio - Stella Caric GmbH, Prinzenstraße 85, Aufgang B1 - Zugang von der Oranienstraße, 10969 Berlin, Germany",
|
||||
location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void geoVariant() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations("geo:52.1333313,11.60000038?z=6");
|
||||
|
@ -251,17 +91,6 @@ public class LocationUriParserTest {
|
|||
Assert.assertNull(location.name);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void googleCalendarWithAddress() throws Exception {
|
||||
final Location[] results = LocationUriParser.parseLocations(
|
||||
"https://maps.google.com/?q=Husemannstra%C3%9Fe,+10435+Berlin,+Germany&ftid=0x47a84e01b6fb4d0b:0x65bf58162bae72fb");
|
||||
Assert.assertEquals(1, results.length);
|
||||
final Location location = results[0];
|
||||
Assert.assertEquals(LocationType.ANY, location.type);
|
||||
Assert.assertFalse(location.hasCoord());
|
||||
Assert.assertEquals("Husemannstraße, 10435 Berlin, Germany", location.name);
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void exceptionBecauseOfScheme() throws Exception {
|
||||
LocationUriParser.parseLocations("foo:bar");
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 0c058ebda031d1fa427bbf78f76c8fc04b45917b
|
||||
Subproject commit c7f77ac4c89b9dbb31625998b9de1dd3d617d68a
|
|
@ -2,10 +2,14 @@ import org.gradle.util.GradleVersion
|
|||
import org.gradle.api.GradleScriptException
|
||||
|
||||
// required Gradle version
|
||||
def minGradleVersion = GradleVersion.version("4.4")
|
||||
def minGradleVersion = GradleVersion.version("4.4") // including
|
||||
def maxGradleVersion = GradleVersion.version("7.0") // excluding
|
||||
|
||||
if (GradleVersion.current() < minGradleVersion)
|
||||
throw new GradleScriptException("build requires Gradle ${minGradleVersion} or later", null)
|
||||
if (GradleVersion.current() < minGradleVersion || GradleVersion.current() >= maxGradleVersion)
|
||||
throw new GradleScriptException("build requires Gradle between ${minGradleVersion.version} (including) and ${maxGradleVersion.version} (excluding)", null)
|
||||
|
||||
gradle.startParameter.excludedTaskNames << "lint"
|
||||
gradle.startParameter.excludedTaskNames << ":oeffi:lintVitalRelease"
|
||||
|
||||
include 'oeffi'
|
||||
include 'public-transport-enabler'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue