Refactor: SDK 28, androidx, ... (#221)

This commit is contained in:
Jonas Bögle 2019-05-06 09:01:33 +02:00 committed by ligi
parent b95ff6d63a
commit a6baee2ca2
157 changed files with 1093 additions and 1134 deletions

1
.gitignore vendored
View file

@ -5,7 +5,6 @@ build
bin bin
gen gen
project.properties project.properties
gradle.properties
local.properties local.properties
*iml *iml

View file

@ -1,5 +1,5 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'spoon' apply plugin: 'com.jaredsburrows.spoon'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
@ -10,20 +10,21 @@ apply plugin: 'com.github.triplet.play'
repositories { repositories {
jcenter() jcenter()
mavenLocal() mavenLocal()
google()
maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
maven { url 'https://maven.google.com' } maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } // For Spoon snapshot, until 2.0.0 is released
} }
android { android {
compileSdkVersion 25 compileSdkVersion 28
buildToolsVersion "25.0.3" buildToolsVersion "28.0.3"
defaultConfig { defaultConfig {
versionCode 349 versionCode 349
versionName "3.4.9" versionName "3.4.9"
minSdkVersion 9 minSdkVersion 14
targetSdkVersion 25 targetSdkVersion 28
applicationId "org.ligi.passandroid" applicationId "org.ligi.passandroid"
testInstrumentationRunner "org.ligi.passandroid.AppReplacingRunner" testInstrumentationRunner "org.ligi.passandroid.AppReplacingRunner"
archivesBaseName = "PassAndroid-$versionName" archivesBaseName = "PassAndroid-$versionName"
@ -62,6 +63,14 @@ android {
} }
} }
// hacky workaround to add spoon task that executes all variants
task spoon {
dependsOn {
tasks.findAll { task -> task.name != 'spoon' && task.name.startsWith('spoon') }
}
}
android.variantFilter { variant -> android.variantFilter { variant ->
def maps = variant.getFlavors().get(0).name def maps = variant.getFlavors().get(0).name
def analytics = variant.getFlavors().get(1).name def analytics = variant.getFlavors().get(1).name
@ -85,7 +94,6 @@ android {
exclude 'META-INF/maven/com.google.guava/guava/pom.properties' exclude 'META-INF/maven/com.google.guava/guava/pom.properties'
exclude 'META-INF/maven/com.google.guava/guava/pom.xml' exclude 'META-INF/maven/com.google.guava/guava/pom.xml'
} }
lintOptions { lintOptions {
@ -100,97 +108,94 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
} }
} }
} compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
configurations { targetCompatibility JavaVersion.VERSION_1_7
}
// http://stackoverflow.com/questions/30578243/why-would-adding-espresso-contrib-cause-an-inflateexception
androidTestCompile.exclude group: 'com.android.support', module: 'appcompat-v7'
androidTestCompile.exclude group: 'com.android.support', module: 'design'
androidTestCompile.exclude group: 'com.android.support', module: 'support-v4'
androidTestCompile.exclude group: 'com.android.support', module: 'support-annotations'
androidTestCompile.exclude group: 'com.android.support', module: 'preference-v7'
androidTestCompile.exclude module: 'recyclerview-v7'
androidTestCompile.exclude module: 'kotlin-stdlib'
} }
dependencies { dependencies {
compile 'com.github.hotchemi:permissionsdispatcher:2.3.2' implementation 'org.permissionsdispatcher:permissionsdispatcher:4.3.0'
kapt 'com.github.hotchemi:permissionsdispatcher-processor:2.3.2' kapt 'org.permissionsdispatcher:permissionsdispatcher-processor:4.3.0'
compile 'com.github.salomonbrys.kodein:kodein:4.1.0' implementation 'com.github.salomonbrys.kodein:kodein:4.1.0'
compileOnly 'org.glassfish:javax.annotation:3.1.1'
provided 'org.glassfish:javax.annotation:10.0-b28' // spoon snapshot, until 2.0.0 is released
androidTestImplementation 'com.squareup.spoon:spoon-client:2.0.0-SNAPSHOT'
androidTestImplementation 'com.github.ligi:trulesk:0.28'
androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.1'
androidTestImplementation 'com.squareup.assertj:assertj-android:1.2.0'
androidTestImplementation "org.mockito:mockito-core:$mockito_version"
androidTestImplementation 'com.linkedin.dexmaker:dexmaker-mockito:2.21.0'
androidTestImplementation 'com.google.code.findbugs:jsr305:3.0.2'
androidTestImplementation 'androidx.appcompat:appcompat:1.0.2'
androidTestImplementation 'com.google.android.material:material:1.0.0'
androidTestCompile 'com.github.ligi:trulesk:0.21' implementation 'com.github.ligi:TouchImageView:2.1'
implementation 'com.github.ligi:ExtraCompats:0.5'
implementation 'net.lingala.zip4j:zip4j:1.3.2'
implementation 'com.jakewharton.threetenabp:threetenabp:1.2.0'
implementation 'org.greenrobot:eventbus:3.1.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
androidTestCompile 'com.android.support.test.espresso:espresso-contrib:3.0.1' implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.preference:preference:1.0.0'
implementation 'androidx.annotation:annotation:1.0.2'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'net.i2p.android.ext:floatingactionbutton:1.10.1'
androidTestCompile 'com.squareup.assertj:assertj-android:1.1.1' implementation 'com.github.ligi:KAXT:0.22'
implementation 'com.github.ligi:KAXTUI:0.8'
implementation 'com.github.ligi:loadtoast:1.10.11'
implementation 'com.github.ligi:tracedroid:2.1'
androidTestCompile "org.mockito:mockito-core:$mockito_version" forPlayImplementation 'com.github.ligi.snackengage:snackengage-playrate:0.18'
androidTestCompile 'com.linkedin.dexmaker:dexmaker-mockito:2.2.0' forFDroidImplementation 'com.github.ligi.snackengage:snackengage-playrate:0.18'
forAmazonImplementation 'com.github.ligi.snackengage:snackengage-amazonrate:0.18'
androidTestCompile 'com.google.code.findbugs:jsr305:3.0.2' // https://medium.com/square-corner-blog/okhttp-3-13-requires-android-5-818bb78d07ce
// Don't update to >=3.13 before minSDK 21 + Java 8
//noinspection GradleDependency
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
androidTestCompile "com.android.support:appcompat-v7:$support_version" implementation 'com.larswerkman:HoloColorPicker:1.5'
androidTestCompile "com.android.support:design:$support_version" implementation 'com.google.code.findbugs:jsr305:3.0.2'
compile 'com.github.ligi:TouchImageView:2.1' // https://github.com/square/moshi/issues/738
compile 'com.github.ligi:ExtraCompats:0.4' // either wait for ProGuard update or use R8 instead (android.enableR8=true)
//noinspection GradleDependency
implementation 'com.squareup.moshi:moshi:1.7.0'
compile 'net.lingala.zip4j:zip4j:1.3.2' implementation 'com.chibatching.kotpref:kotpref:2.6.0'
compile 'com.jakewharton.threetenabp:threetenabp:1.1.0' implementation 'com.chibatching.kotpref:initializer:2.6.0'
compile 'org.greenrobot:eventbus:3.0.0' testImplementation 'androidx.annotation:annotation:1.0.2'
testImplementation 'com.squareup.assertj:assertj-android:1.2.0'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" testImplementation 'junit:junit:4.12'
testImplementation "org.mockito:mockito-core:$mockito_version"
compile "com.android.support:support-annotations:$support_version" testImplementation 'org.threeten:threetenbp:1.3.8'
compile "com.android.support:recyclerview-v7:$support_version"
compile "com.android.support:appcompat-v7:$support_version"
compile "com.android.support:cardview-v7:$support_version"
compile "com.android.support:design:$support_version"
compile "com.android.support:preference-v7:$support_version"
compile 'net.i2p.android.ext:floatingactionbutton:1.10.1'
compile 'com.github.ligi:KAXT:0.20'
compile 'com.github.ligi:KAXTUI:0.4'
compile 'com.github.ligi:loadtoast:1.10.11'
compile 'com.github.ligi:tracedroid:1.4'
forPlayCompile 'com.github.ligi.snackengage:snackengage-playrate:0.15'
forFDroidCompile 'com.github.ligi.snackengage:snackengage-playrate:0.15'
forAmazonCompile 'com.github.ligi.snackengage:snackengage-amazonrate:0.15'
compile 'com.squareup.okhttp3:okhttp:3.11.0'
compile 'com.larswerkman:HoloColorPicker:1.5'
compile 'com.google.code.findbugs:jsr305:3.0.2'
compile 'com.squareup.moshi:moshi:1.4.0'
compile "com.chibatching.kotpref:kotpref:2.6.0"
compile "com.chibatching.kotpref:initializer:2.6.0"
testCompile "com.android.support:support-annotations:$support_version"
testCompile 'com.squareup.assertj:assertj-android:1.1.1'
testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:${mockito_version}"
testCompile 'org.threeten:threetenbp:1.3.7'
// https://github.com/ligi/PassAndroid/issues/181 // https://github.com/ligi/PassAndroid/issues/181
// Don't update to 3.3.1 before minSDK 19 - or replace zxing // Don't upgrade before minSDK 19 - or replace zxing
compile 'com.google.zxing:core:3.3.0' //noinspection GradleDependency
implementation 'com.google.zxing:core:3.3.0'
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4' debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3'
withAnalyticsCompile "com.google.android.gms:play-services-analytics:$play_version" // requires minSDK 16 according to docs, not sure if it causes an issue
withMapsCompile "com.google.android.gms:play-services-maps:$play_version" withAnalyticsImplementation 'com.google.android.gms:play-services-analytics:16.0.8'
withMapsImplementation 'com.google.android.gms:play-services-maps:16.1.0'
} }
spoon { spoon {
debug = true debug = true
grantAllPermissions = true grantAll = true
baseOutputDir = "build/spoon"
} }
play { play {

View file

@ -20,9 +20,9 @@
# If your project uses WebView with JS, uncomment the following # If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface # and specify the fully qualified class name to the JavaScript interface
# class: # class:
-keepclassmembers class fqcn.of.javascript.interface.for.webview { #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
public *; # public *;
} #}
# optimize # optimize
-optimizationpasses 2 -optimizationpasses 2
@ -30,12 +30,6 @@
-dontusemixedcaseclassnames -dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses -dontskipnonpubliclibraryclasses
# AppCompat
-dontwarn android.support.v7.**
-keep class android.support.v7.** { *; }
-keep interface android.support.v7.** { *; }
# Keep line numbers to alleviate debugging stack traces # Keep line numbers to alleviate debugging stack traces
-renamesourcefileattribute SourceFile -renamesourcefileattribute SourceFile
@ -44,7 +38,6 @@
### for api client ### for api client
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault -keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
-keepclassmembers class * { -keepclassmembers class * {
@ -54,7 +47,6 @@
# Needed by Guava # Needed by Guava
# See https://groups.google.com/forum/#!topic/guava-discuss/YCZzeCiIVoI # See https://groups.google.com/forum/#!topic/guava-discuss/YCZzeCiIVoI
-dontwarn sun.misc.Unsafe -dontwarn sun.misc.Unsafe
-dontwarn com.google.common.collect.MinMaxPriorityQueue -dontwarn com.google.common.collect.MinMaxPriorityQueue
@ -72,9 +64,6 @@
-keep class **$$ViewBinder { *; } -keep class **$$ViewBinder { *; }
-keepnames class * { @butterknife.Bind *;} -keepnames class * { @butterknife.Bind *;}
#### for support 22
-dontwarn android.support.**
#### for guava #### for guava
-dontwarn javax.annotation.** -dontwarn javax.annotation.**
-dontwarn javax.inject.** -dontwarn javax.inject.**
@ -105,23 +94,20 @@
-dontwarn java.nio.file.OpenOption -dontwarn java.nio.file.OpenOption
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-keep public class com.google.android.gms.**
-dontwarn com.google.android.gms.**
## New rules for EventBus 3.0.x ## ## New rules for EventBus 3.0.x ##
# http://greenrobot.org/eventbus/documentation/proguard/ # http://greenrobot.org/eventbus/documentation/proguard/
-keepattributes *Annotation* -keepattributes *Annotation*
-keepclassmembers class ** { -keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe <methods>; @org.greenrobot.eventbus.Subscribe <methods>;
} }
-keep enum org.greenrobot.eventbus.ThreadMode { *; } -keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor # Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent { -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
<init>(java.lang.Throwable); <init>(java.lang.Throwable);
} }
### for moshi ### for moshi

View file

@ -15,7 +15,7 @@
"message":"", "message":"",
"transfer":"barcode_QR", "transfer":"barcode_QR",
"alternative": { "alternative": {
"order":1, "order":1
} }
}, },

View file

@ -60,6 +60,6 @@ class TestApp : App() {
fixedPassListPassStore().setList(emptyList()) fixedPassListPassStore().setList(emptyList())
} }
fun fixedPassListPassStore() = passStore() as FixedPassListPassStore private fun fixedPassListPassStore() = passStore() as FixedPassListPassStore
} }
} }

View file

@ -3,14 +3,14 @@ package org.ligi.passandroid
import android.app.Activity.RESULT_CANCELED import android.app.Activity.RESULT_CANCELED
import android.app.Instrumentation import android.app.Instrumentation
import android.provider.CalendarContract import android.provider.CalendarContract
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.intent.Intents.intended import androidx.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.intending import androidx.test.espresso.intent.Intents.intending
import android.support.test.espresso.intent.matcher.IntentMatchers.hasExtra import androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra
import android.support.test.espresso.intent.matcher.IntentMatchers.hasType import androidx.test.espresso.intent.matcher.IntentMatchers.hasType
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import org.hamcrest.CoreMatchers.not import org.hamcrest.CoreMatchers.not
import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.allOf
import org.junit.Rule import org.junit.Rule
@ -23,8 +23,8 @@ import org.threeten.bp.ZonedDateTime
class TheAddToCalendar { class TheAddToCalendar {
val time = ZonedDateTime.now() private val time = ZonedDateTime.now()
val time2 = ZonedDateTime.now().plusHours(3) private val time2 = ZonedDateTime.now().plusHours(3)
@get:Rule @get:Rule
var rule = TruleskIntentRule(PassListActivity::class.java, false) var rule = TruleskIntentRule(PassListActivity::class.java, false)

View file

@ -1,13 +1,13 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.support.test.espresso.Espresso.closeSoftKeyboard import androidx.test.espresso.Espresso.closeSoftKeyboard
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.* import androidx.test.espresso.action.ViewActions.*
import android.support.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import android.support.test.filters.SdkSuppress import androidx.test.ext.junit.runners.AndroidJUnit4
import android.support.test.runner.AndroidJUnit4 import androidx.test.filters.SdkSuppress
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
@ -27,9 +27,11 @@ class TheBarCodeEditing {
val passStore: PassStore = App.kodein.instance() val passStore: PassStore = App.kodein.instance()
lateinit var currentPass: PassImpl private lateinit var currentPass: PassImpl
fun start(setupPass: (pass: PassImpl) -> Unit = {}) { private fun start(setupPass: (pass: PassImpl) -> Unit = {}) {
TestApp.populatePassStoreWithSinglePass()
currentPass = passStore.currentPass as PassImpl currentPass = passStore.currentPass as PassImpl

View file

@ -1,6 +1,5 @@
package org.ligi.passandroid package org.ligi.passandroid
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.api.Fail.fail import org.assertj.core.api.Fail.fail
import org.junit.Test import org.junit.Test
@ -48,7 +47,6 @@ class TheBarcodeHelper {
} catch (e: Exception) { } catch (e: Exception) {
fail("could not create barcode", e) fail("could not create barcode", e)
} }
} }
fun testBitmapSizeIsSane(format: PassBarCodeFormat) { fun testBitmapSizeIsSane(format: PassBarCodeFormat) {
@ -59,6 +57,5 @@ class TheBarcodeHelper {
} catch (e: Exception) { } catch (e: Exception) {
fail("could not create barcode", e) fail("could not create barcode", e)
} }
} }
} }

View file

@ -1,9 +1,9 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import org.hamcrest.CoreMatchers.containsString import org.hamcrest.CoreMatchers.containsString
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

View file

@ -1,10 +1,10 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.ligi.passandroid.R.id.emptyView import org.ligi.passandroid.R.id.emptyView

View file

@ -1,10 +1,10 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.replaceText import androidx.test.espresso.action.ViewActions.replaceText
import android.support.test.espresso.action.ViewActions.scrollTo import androidx.test.espresso.action.ViewActions.scrollTo
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

View file

@ -2,10 +2,10 @@ package org.ligi.passandroid
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import android.widget.ImageView import android.widget.ImageView
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
@ -19,9 +19,9 @@ import org.ligi.passandroid.ui.FullscreenBarcodeActivity
import org.ligi.trulesk.TruleskIntentRule import org.ligi.trulesk.TruleskIntentRule
import java.util.* import java.util.*
class TheFullscreenBarcodeActivity { private const val BARCODE_MESSAGE = "2323"
private val BARCODE_MESSAGE = "2323" class TheFullscreenBarcodeActivity {
@get:Rule @get:Rule
var rule = TruleskIntentRule(FullscreenBarcodeActivity::class.java, false) var rule = TruleskIntentRule(FullscreenBarcodeActivity::class.java, false)
@ -78,11 +78,11 @@ class TheFullscreenBarcodeActivity {
val bitmap = bitmapDrawable.bitmap val bitmap = bitmapDrawable.bitmap
val bitmapToTest: Bitmap val bitmapToTest: Bitmap
if (format === PassBarCodeFormat.AZTEC) { bitmapToTest = if (format === PassBarCodeFormat.AZTEC) {
// not sure why - but for the decoder to pick up AZTEC it must have moar pixelz - smells like a zxing bug // not sure why - but for the decoder to pick up AZTEC it must have moar pixelz - smells like a zxing bug
bitmapToTest = Bitmap.createScaledBitmap(bitmap, bitmap.width * 2, bitmap.height * 2, false) Bitmap.createScaledBitmap(bitmap, bitmap.width * 2, bitmap.height * 2, false)
} else { } else {
bitmapToTest = bitmap bitmap
} }
assertThat(bitmapToTest.decodeBarCode()).isEqualTo(BARCODE_MESSAGE) assertThat(bitmapToTest.decodeBarCode()).isEqualTo(BARCODE_MESSAGE)

View file

@ -1,9 +1,9 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

View file

@ -5,15 +5,15 @@ import android.app.Activity.RESULT_CANCELED
import android.app.Instrumentation.ActivityResult import android.app.Instrumentation.ActivityResult
import android.content.Intent.ACTION_SEND import android.content.Intent.ACTION_SEND
import android.content.Intent.ACTION_VIEW import android.content.Intent.ACTION_VIEW
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.Espresso.pressBack import androidx.test.espresso.Espresso.pressBack
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.contrib.DrawerActions.open import androidx.test.espresso.contrib.DrawerActions.open
import android.support.test.espresso.intent.Intents.intended import androidx.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.intending import androidx.test.espresso.intent.Intents.intending
import android.support.test.espresso.intent.matcher.IntentMatchers.* import androidx.test.espresso.intent.matcher.IntentMatchers.*
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.allOf
import org.hamcrest.Matchers.not import org.hamcrest.Matchers.not
import org.junit.Rule import org.junit.Rule
@ -61,19 +61,6 @@ class TheNavigationDrawer {
intended(allOf(hasAction(ACTION_VIEW), hasData("https://play.google.com/apps/testing/org.ligi.passandroid"))) intended(allOf(hasAction(ACTION_VIEW), hasData("https://play.google.com/apps/testing/org.ligi.passandroid")))
} }
@Test
fun testCommunityClick() {
testThatNavigationDrawerOpens()
rule.screenShot("open_drawer")
intending(hasAction(ACTION_VIEW)).respondWith(ActivityResult(RESULT_CANCELED, null))
onView(withText(nav_community_on_google)).perform(click())
intended(allOf(hasAction(ACTION_VIEW), hasData("https://plus.google.com/communities/116353894782342292067")))
}
@Test @Test
fun testGitHubClick() { fun testGitHubClick() {
testThatNavigationDrawerOpens() testThatNavigationDrawerOpens()

View file

@ -4,18 +4,16 @@ import android.annotation.TargetApi
import android.app.Activity import android.app.Activity
import android.app.Instrumentation import android.app.Instrumentation
import android.content.Intent import android.content.Intent
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.* import androidx.test.espresso.action.ViewActions.*
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.intent.Intents.intended import androidx.test.espresso.intent.Intents.intended
import android.support.test.espresso.intent.Intents.intending import androidx.test.espresso.intent.Intents.intending
import android.support.test.espresso.intent.matcher.IntentMatchers.hasAction import androidx.test.espresso.intent.matcher.IntentMatchers.hasAction
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.ligi.passandroid.R.id.*
import org.ligi.passandroid.R.string.*
import org.ligi.passandroid.model.pass.PassType.COUPON import org.ligi.passandroid.model.pass.PassType.COUPON
import org.ligi.passandroid.model.pass.PassType.EVENT import org.ligi.passandroid.model.pass.PassType.EVENT
import org.ligi.passandroid.ui.PassEditActivity import org.ligi.passandroid.ui.PassEditActivity
@ -27,15 +25,16 @@ class ThePassEditActivity {
val passStore = TestApp.passStore() val passStore = TestApp.passStore()
@get:Rule @get:Rule
var rule = TruleskIntentRule(PassEditActivity::class.java) var rule = TruleskIntentRule(PassEditActivity::class.java) {
TestApp.populatePassStoreWithSinglePass()
}
@Test @Test
fun testSetToEventWorks() { fun testSetToEventWorks() {
onView(withId(R.id.categoryView)).perform(click())
onView(withId(categoryView)).perform(click()) onView(withText(R.string.select_category_dialog_title)).perform(click())
onView(withText(R.string.category_event)).perform(click())
onView(withText(select_category_dialog_title)).perform(click())
onView(withText(category_event)).perform(click())
assertThat(passStore.currentPass!!.type).isEqualTo(EVENT) assertThat(passStore.currentPass!!.type).isEqualTo(EVENT)
rule.screenShot("edit_set_event") rule.screenShot("edit_set_event")
@ -43,10 +42,10 @@ class ThePassEditActivity {
@Test @Test
fun testSetToCouponWorks() { fun testSetToCouponWorks() {
onView(withId(categoryView)).perform(click()) onView(withId(R.id.categoryView)).perform(click())
onView(withText(select_category_dialog_title)).perform(click()) onView(withText(R.string.select_category_dialog_title)).perform(click())
onView(withText(category_coupon)).perform(click()) onView(withText(R.string.category_coupon)).perform(click())
assertThat(passStore.currentPass!!.type).isEqualTo(COUPON) assertThat(passStore.currentPass!!.type).isEqualTo(COUPON)
rule.screenShot("edit_set_coupon") rule.screenShot("edit_set_coupon")
@ -55,7 +54,7 @@ class ThePassEditActivity {
@Test @Test
fun testSetDescriptionWorks() { fun testSetDescriptionWorks() {
onView(withId(passTitle)).perform(clearText(), typeText("test description")) onView(withId(R.id.passTitle)).perform(clearText(), typeText("test description"))
assertThat(passStore.currentPass!!.description).isEqualTo("test description") assertThat(passStore.currentPass!!.description).isEqualTo("test description")
rule.screenShot("edit_set_description") rule.screenShot("edit_set_description")
@ -65,10 +64,10 @@ class ThePassEditActivity {
@Test @Test
fun testColorWheelIsThere() { fun testColorWheelIsThere() {
onView(withId(categoryView)).perform(click()) onView(withId(R.id.categoryView)).perform(click())
onView(withText(change_color_dialog_title)).perform(click()) onView(withText(R.string.change_color_dialog_title)).perform(click())
onView(withId(colorPicker)).check(matches(isDisplayed())) onView(withId(R.id.colorPicker)).check(matches(isDisplayed()))
rule.screenShot("edit_set_color") rule.screenShot("edit_set_color")
} }

View file

@ -2,11 +2,11 @@ package org.ligi.passandroid
import android.annotation.TargetApi import android.annotation.TargetApi
import android.os.Build import android.os.Build
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.Espresso.pressBack import androidx.test.espresso.Espresso.pressBack
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.ligi.passandroid.R.id.pass_recyclerview import org.ligi.passandroid.R.id.pass_recyclerview

View file

@ -1,11 +1,11 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.action.ViewActions.typeText import androidx.test.espresso.action.ViewActions.typeText
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import android.support.v7.widget.helper.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -14,6 +14,8 @@ import org.ligi.passandroid.ui.PassListActivity
import org.ligi.passandroid.ui.PassListFragment import org.ligi.passandroid.ui.PassListFragment
import org.ligi.trulesk.TruleskIntentRule import org.ligi.trulesk.TruleskIntentRule
const val CUSTOM_PROBE = "FOO_PROBE"
class ThePassListSwiping { class ThePassListSwiping {
@get:Rule @get:Rule
@ -42,7 +44,6 @@ class ThePassListSwiping {
@Test @Test
fun testWeCanMoveToCustom() { fun testWeCanMoveToCustom() {
val CUSTOM_PROBE = "FOO_PROBE"
fakeSwipeLeft() fakeSwipeLeft()

View file

@ -1,12 +1,13 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.annotation.TargetApi import android.annotation.TargetApi
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.* import androidx.test.espresso.matcher.ViewMatchers.*
import org.hamcrest.core.IsNot.not import org.hamcrest.core.IsNot.not
import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.ligi.passandroid.model.pass.BarCode import org.ligi.passandroid.model.pass.BarCode
@ -21,11 +22,16 @@ import java.util.*
@TargetApi(14) @TargetApi(14)
class ThePassViewActivity { class ThePassViewActivity {
internal fun getActPass() = TestApp.passStore().currentPass as PassImpl private fun getActPass() = TestApp.passStore().currentPass as PassImpl
@get:Rule @get:Rule
var rule = TruleskActivityRule(PassViewActivity::class.java, false) var rule = TruleskActivityRule(PassViewActivity::class.java, false)
@Before
fun before() {
TestApp.populatePassStoreWithSinglePass()
}
@Test @Test
fun testThatDescriptionIsThere() { fun testThatDescriptionIsThere() {
rule.launchActivity(null) rule.launchActivity(null)
@ -35,7 +41,7 @@ class ThePassViewActivity {
@Test @Test
fun testDateIsGoneWhenPassbookHasNoDate() { fun testDateIsGoneWhenPassbookHasNoDate() {
getActPass().validTimespans = ArrayList<PassImpl.TimeSpan>() getActPass().validTimespans = ArrayList()
rule.launchActivity(null) rule.launchActivity(null)
onView(withId(R.id.date)).check(matches(not(isDisplayed()))) onView(withId(R.id.date)).check(matches(not(isDisplayed())))
@ -92,7 +98,7 @@ class ThePassViewActivity {
@Test @Test
fun testLinkToCalendarIsNotThereWhenPassbookHasNoDate() { fun testLinkToCalendarIsNotThereWhenPassbookHasNoDate() {
getActPass().validTimespans = ArrayList<PassImpl.TimeSpan>() getActPass().validTimespans = ArrayList()
rule.launchActivity(null) rule.launchActivity(null)
onView(withText(R.string.pass_to_calendar)).check(matches(not(isDisplayed()))) onView(withText(R.string.pass_to_calendar)).check(matches(not(isDisplayed())))

View file

@ -1,9 +1,9 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions import androidx.test.espresso.assertion.ViewAssertions
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import org.hamcrest.CoreMatchers.not import org.hamcrest.CoreMatchers.not
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -16,7 +16,10 @@ import org.threeten.bp.ZonedDateTime
class ThePassViewHolder { class ThePassViewHolder {
val currentPass by lazy { App.passStore.currentPass as PassImpl } private val currentPass by lazy {
TestApp.populatePassStoreWithSinglePass()
App.passStore.currentPass as PassImpl
}
@get:Rule @get:Rule
var rule = TruleskActivityRule(PassListActivity::class.java, false) var rule = TruleskActivityRule(PassListActivity::class.java, false)

View file

@ -2,7 +2,7 @@ package org.ligi.passandroid
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.support.test.InstrumentationRegistry.getInstrumentation import androidx.test.platform.app.InstrumentationRegistry
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.After import org.junit.After
import org.junit.Rule import org.junit.Rule
@ -17,13 +17,14 @@ class ThePastLocationsStore {
@get:Rule @get:Rule
var rule = TruleskActivityRule(PassViewActivity::class.java) { var rule = TruleskActivityRule(PassViewActivity::class.java) {
TestApp.populatePassStoreWithSinglePass()
MockitoAnnotations.initMocks(this) MockitoAnnotations.initMocks(this)
} }
@Mock @Mock
lateinit var tracker: Tracker lateinit var tracker: Tracker
val prefs: SharedPreferences by lazy { getInstrumentation().context.getSharedPreferences("" + System.currentTimeMillis() / 100000, Context.MODE_PRIVATE) } private val prefs: SharedPreferences by lazy { InstrumentationRegistry.getInstrumentation().context.getSharedPreferences("" + System.currentTimeMillis() / 100000, Context.MODE_PRIVATE) }
@After @After
fun tearDown() { fun tearDown() {
@ -34,7 +35,7 @@ class ThePastLocationsStore {
fun testPastLocationsStoreShouldNeverContainMoreThanMaxElements() { fun testPastLocationsStoreShouldNeverContainMoreThanMaxElements() {
val tested = PastLocationsStore(prefs, tracker) val tested = PastLocationsStore(prefs, tracker)
for (i in 0..PastLocationsStore.MAX_ELEMENTS * 2 - 1) { for (i in 0 until PastLocationsStore.MAX_ELEMENTS * 2) {
tested.putLocation("" + i) tested.putLocation("" + i)
} }
@ -44,7 +45,7 @@ class ThePastLocationsStore {
@Test @Test
fun testPastLocationsStoreShouldStoreOnlyOneOfAKind() { fun testPastLocationsStoreShouldStoreOnlyOneOfAKind() {
val tested = PastLocationsStore(prefs, tracker!!) val tested = PastLocationsStore(prefs, tracker)
for (i in 0..2) { for (i in 0..2) {
tested.putLocation("foo") tested.putLocation("foo")

View file

@ -1,10 +1,10 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.os.Build import android.os.Build
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.click import androidx.test.espresso.action.ViewActions.click
import android.support.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.matcher.ViewMatchers.withText
import android.support.v7.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test
@ -20,7 +20,7 @@ class ThePreferenceActivity {
@get:Rule @get:Rule
val rule = TruleskActivityRule(PreferenceActivity::class.java) val rule = TruleskActivityRule(PreferenceActivity::class.java)
val androidSettings by lazy { AndroidSettings(rule.activity) } private val androidSettings by lazy { AndroidSettings(rule.activity) }
@Test @Test
fun autoLightToggles() { fun autoLightToggles() {

View file

@ -1,6 +1,6 @@
package org.ligi.passandroid; package org.ligi.passandroid;
import android.support.test.InstrumentationRegistry; import androidx.test.platform.app.InstrumentationRegistry;
import java.io.InputStream; import java.io.InputStream;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -27,7 +27,7 @@ public class TheUnzipPassController {
PassStore passStore; PassStore passStore;
@Before @Before
public void setUp() throws Exception { public void setUp() {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
} }

View file

@ -1,8 +1,8 @@
package org.ligi.passandroid.functions package org.ligi.passandroid.functions
import android.support.test.espresso.UiController import androidx.test.espresso.UiController
import android.support.test.espresso.ViewAction import androidx.test.espresso.ViewAction
import android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom
import android.view.View import android.view.View
import net.i2p.android.ext.floatingactionbutton.FloatingActionsMenu import net.i2p.android.ext.floatingactionbutton.FloatingActionsMenu
import org.hamcrest.Description import org.hamcrest.Description

View file

@ -1,12 +1,11 @@
package org.ligi.passandroid.functions package org.ligi.passandroid.functions
import android.support.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.onView
import android.support.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import android.support.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withId
import org.ligi.passandroid.R import org.ligi.passandroid.R
fun checkThatHelpIsThere() { fun checkThatHelpIsThere() {
onView(withId(R.id.help_text)).check(matches(isDisplayed())) onView(withId(R.id.help_text)).check(matches(isDisplayed()))
} }

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.functions package org.ligi.passandroid.functions
import android.content.Context import android.content.Context
import android.support.test.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry
import org.assertj.core.api.Fail.fail import org.assertj.core.api.Fail.fail
import org.ligi.passandroid.model.InputStreamWithSource import org.ligi.passandroid.model.InputStreamWithSource
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore

View file

@ -10,7 +10,7 @@ class FixedPassListPassStore(private var passes: List<Pass>) : PassStore {
override lateinit var classifier: PassClassifier override lateinit var classifier: PassClassifier
init { init {
classifier = PassClassifier(HashMap<String, String>(), this) classifier = PassClassifier(HashMap(), this)
} }
fun setList(newPasses: List<Pass>, newCurrentPass: Pass? = newPasses.firstOrNull()) { fun setList(newPasses: List<Pass>, newCurrentPass: Pass? = newPasses.firstOrNull()) {
@ -19,7 +19,7 @@ class FixedPassListPassStore(private var passes: List<Pass>) : PassStore {
passMap.clear() passMap.clear()
passMap.putAll(createHashMap()) passMap.putAll(createHashMap())
classifier = PassClassifier(HashMap<String, String>(), this) classifier = PassClassifier(HashMap(), this)
} }
override var currentPass: Pass? = null override var currentPass: Pass? = null
@ -31,7 +31,7 @@ class FixedPassListPassStore(private var passes: List<Pass>) : PassStore {
private fun createHashMap(): HashMap<String, Pass> { private fun createHashMap(): HashMap<String, Pass> {
val hashMap = HashMap<String, Pass>() val hashMap = HashMap<String, Pass>()
passes.forEach { hashMap.put(it.id, it) } passes.forEach { hashMap[it.id] = it }
return hashMap return hashMap
} }

View file

@ -29,6 +29,7 @@
<receiver <receiver
android:name=".InstallListener" android:name=".InstallListener"
android:permission="android.permission.INSTALL_PACKAGES"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER"/> <action android:name="com.android.vending.INSTALL_REFERRER"/>
@ -36,7 +37,7 @@
</receiver> </receiver>
<provider <provider
android:name="android.support.v4.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="@string/authority_fileprovider" android:authorities="@string/authority_fileprovider"
android:grantUriPermissions="true" android:grantUriPermissions="true"
android:exported="false"> android:exported="false">
@ -122,47 +123,35 @@
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="application/vnd.espass-espass"/> <data android:scheme="http" android:mimeType="application/vnd.espass-espass"/>
</intent-filter> <data android:scheme="https" android:mimeType="application/vnd.espass-espass"/>
<intent-filter> <data android:scheme="content" android:mimeType="application/vnd.espass-espass"/>
<action android:name="android.intent.action.VIEW"/> <data android:scheme="file" android:mimeType="application/vnd.espass-espass"/>
<category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http" android:mimeType="application/vnd.espass-espass+zip"/>
<category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="https" android:mimeType="application/vnd.espass-espass+zip"/>
<data android:scheme="content" android:mimeType="application/vnd.espass-espass+zip"/>
<data android:scheme="file" android:mimeType="application/vnd.espass-espass+zip"/>
<data android:mimeType="application/vnd.espass-espass+zip"/> <data android:scheme="http" android:mimeType="application/vnd.apple.pkpass"/>
</intent-filter> <data android:scheme="https" android:mimeType="application/vnd.apple.pkpass"/>
<intent-filter> <data android:scheme="content" android:mimeType="application/vnd.apple.pkpass"/>
<action android:name="android.intent.action.VIEW"/> <data android:scheme="file" android:mimeType="application/vnd.apple.pkpass"/>
<category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http" android:mimeType="application/pkpass"/>
<category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="https" android:mimeType="application/pkpass"/>
<data android:scheme="content" android:mimeType="application/pkpass"/>
<data android:scheme="file" android:mimeType="application/pkpass"/>
<data android:mimeType="application/vnd.apple.pkpass"/> <data android:scheme="http" android:mimeType="application/vndapplepkpass"/>
</intent-filter> <data android:scheme="https" android:mimeType="application/vndapplepkpass"/>
<intent-filter> <data android:scheme="content" android:mimeType="application/vndapplepkpass"/>
<action android:name="android.intent.action.VIEW"/> <data android:scheme="file" android:mimeType="application/vndapplepkpass"/>
<category android:name="android.intent.category.DEFAULT"/> <data android:scheme="http" android:mimeType="application/vnd-com.apple.pkpass"/>
<category android:name="android.intent.category.BROWSABLE"/> <data android:scheme="https" android:mimeType="application/vnd-com.apple.pkpass"/>
<data android:scheme="content" android:mimeType="application/vnd-com.apple.pkpass"/>
<data android:mimeType="application/pkpass"/> <data android:scheme="file" android:mimeType="application/vnd-com.apple.pkpass"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="application/vndapplepkpass"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="application/vnd-com.apple.pkpass"/>
</intent-filter> </intent-filter>
<intent-filter> <intent-filter>
@ -616,17 +605,9 @@
<category android:name="android.intent.category.DEFAULT"/> <category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/> <category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="application/x-pdf"/> <data android:scheme="content" android:mimeType="application/x-pdf"/>
<data android:scheme="content" android:mimeType="application/pdf"/>
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="application/pdf"/>
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>
@ -1071,22 +1052,6 @@
android:pathPattern="/.*\\.pkpass" android:pathPattern="/.*\\.pkpass"
android:scheme="content"/> android:scheme="content"/>
</intent-filter> </intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="application/vnd.apple.pkpass"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="application/vnd-com.apple.pkpass"/>
</intent-filter>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW"/> <action android:name="android.intent.action.VIEW"/>

View file

@ -1,9 +1,9 @@
/** /*
******************************************************************************* *******************************************************************************
* Copyright (C) 2005-2014, International Business Machines Corporation and * * Copyright (C) 2005 - 2012, International Business Machines Corporation and *
* others. All Rights Reserved. * * others. All Rights Reserved. *
******************************************************************************* *******************************************************************************
*/ */
package com.ibm.icu.text; package com.ibm.icu.text;
import java.io.IOException; import java.io.IOException;
@ -35,6 +35,7 @@ import java.util.List;
* <p/> * <p/>
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
@SuppressWarnings("ALL")
public class CharsetDetector { public class CharsetDetector {
// Question: Should we have getters corresponding to the setters for input text // Question: Should we have getters corresponding to the setters for input text
@ -182,7 +183,7 @@ public class CharsetDetector {
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public CharsetMatch[] detectAll() { public CharsetMatch[] detectAll() {
ArrayList<CharsetMatch> matches = new ArrayList<CharsetMatch>(); ArrayList<CharsetMatch> matches = new ArrayList<>();
MungeInput(); // Strip html markup, collect byte stats. MungeInput(); // Strip html markup, collect byte stats.
@ -344,7 +345,7 @@ public class CharsetDetector {
* it by removing what appears to be html markup. * it by removing what appears to be html markup.
*/ */
private void MungeInput() { private void MungeInput() {
int srci = 0; int srci;
int dsti = 0; int dsti = 0;
byte b; byte b;
boolean inMarkup = false; boolean inMarkup = false;
@ -473,7 +474,7 @@ public class CharsetDetector {
private static final List<CSRecognizerInfo> ALL_CS_RECOGNIZERS; private static final List<CSRecognizerInfo> ALL_CS_RECOGNIZERS;
static { static {
List<CSRecognizerInfo> list = new ArrayList<CSRecognizerInfo>(); List<CSRecognizerInfo> list = new ArrayList<>();
list.add(new CSRecognizerInfo(new CharsetRecog_UTF8(), true)); list.add(new CSRecognizerInfo(new CharsetRecog_UTF8(), true));
list.add(new CSRecognizerInfo(new CharsetRecog_Unicode.CharsetRecog_UTF_16_BE(), true)); list.add(new CSRecognizerInfo(new CharsetRecog_Unicode.CharsetRecog_UTF_16_BE(), true));
@ -522,7 +523,7 @@ public class CharsetDetector {
*/ */
@Deprecated @Deprecated
public String[] getDetectableCharsets() { public String[] getDetectableCharsets() {
List<String> csnames = new ArrayList<String>(ALL_CS_RECOGNIZERS.size()); List<String> csnames = new ArrayList<>(ALL_CS_RECOGNIZERS.size());
for (int i = 0; i < ALL_CS_RECOGNIZERS.size(); i++) { for (int i = 0; i < ALL_CS_RECOGNIZERS.size(); i++) {
CSRecognizerInfo rcinfo = ALL_CS_RECOGNIZERS.get(i); CSRecognizerInfo rcinfo = ALL_CS_RECOGNIZERS.get(i);
boolean active = (fEnabledRecognizers == null) ? rcinfo.isDefaultEnabled : fEnabledRecognizers[i]; boolean active = (fEnabledRecognizers == null) ? rcinfo.isDefaultEnabled : fEnabledRecognizers[i];
@ -530,7 +531,7 @@ public class CharsetDetector {
csnames.add(rcinfo.recognizer.getName()); csnames.add(rcinfo.recognizer.getName());
} }
} }
return csnames.toArray(new String[csnames.size()]); return csnames.toArray(new String[0]);
} }
/** /**

View file

@ -1,9 +1,9 @@
/** /*
******************************************************************************* *******************************************************************************
* Copyright (C) 2005-2012, International Business Machines Corporation and * * Copyright (C) 2005 - 2012, International Business Machines Corporation and *
* others. All Rights Reserved. * * others. All Rights Reserved. *
******************************************************************************* *******************************************************************************
*/ */
package com.ibm.icu.text; package com.ibm.icu.text;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@ -26,6 +26,7 @@ import java.io.Reader;
* *
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
@SuppressWarnings("ALL")
public class CharsetMatch implements Comparable<CharsetMatch> { public class CharsetMatch implements Comparable<CharsetMatch> {
@ -85,13 +86,13 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* @stable ICU 3.4 * @stable ICU 3.4
*/ */
public String getString(int maxLength) throws java.io.IOException { public String getString(int maxLength) throws java.io.IOException {
String result = null; String result;
if (fInputStream != null) { if (fInputStream != null) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
char[] buffer = new char[1024]; char[] buffer = new char[1024];
Reader reader = getReader(); Reader reader = getReader();
int max = maxLength < 0? Integer.MAX_VALUE : maxLength; int max = maxLength < 0? Integer.MAX_VALUE : maxLength;
int bytesRead = 0; int bytesRead;
while ((bytesRead = reader.read(buffer, 0, Math.min(max, 1024))) >= 0) { while ((bytesRead = reader.read(buffer, 0, Math.min(max, 1024))) >= 0) {
sb.append(buffer, 0, bytesRead); sb.append(buffer, 0, bytesRead);
@ -108,6 +109,7 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
* be used to open a charset (e.g. IBM424_rtl). The ending '_rtl' or 'ltr' * be used to open a charset (e.g. IBM424_rtl). The ending '_rtl' or 'ltr'
* should be stripped off before creating the string. * should be stripped off before creating the string.
*/ */
//noinspection IndexOfReplaceableByContains
int startSuffix = name.indexOf("_rtl") < 0 ? name.indexOf("_ltr") : name.indexOf("_rtl"); int startSuffix = name.indexOf("_rtl") < 0 ? name.indexOf("_ltr") : name.indexOf("_rtl");
if (startSuffix > 0) { if (startSuffix > 0) {
name = name.substring(0, startSuffix); name = name.substring(0, startSuffix);
@ -234,7 +236,7 @@ public class CharsetMatch implements Comparable<CharsetMatch> {
// If user gave us a byte array, this is it. // If user gave us a byte array, this is it.
private int fRawLength; // Length of data in fRawInput array. private int fRawLength; // Length of data in fRawInput array.
private InputStream fInputStream = null; // User's input stream, or null if the user private InputStream fInputStream; // User's input stream, or null if the user
// gave us a byte array. // gave us a byte array.
private String fCharsetName; // The name of the charset this CharsetMatch private String fCharsetName; // The name of the charset this CharsetMatch

View file

@ -1,9 +1,9 @@
/* /*
******************************************************************************* *******************************************************************************
* Copyright (C) 2005 - 2012, International Business Machines Corporation and * * Copyright (C) 2005 - 2012, International Business Machines Corporation and *
* others. All Rights Reserved. * * others. All Rights Reserved. *
******************************************************************************* *******************************************************************************
*/ */
package com.ibm.icu.text; package com.ibm.icu.text;
/** /**
@ -14,6 +14,7 @@ package com.ibm.icu.text;
* *
* The separate classes are nested within this class. * The separate classes are nested within this class.
*/ */
@SuppressWarnings("ALL")
abstract class CharsetRecog_2022 extends CharsetRecognizer { abstract class CharsetRecog_2022 extends CharsetRecognizer {
@ -44,7 +45,7 @@ abstract class CharsetRecog_2022 extends CharsetRecognizer {
byte [] seq = escapeSequences[escN]; byte [] seq = escapeSequences[escN];
if ((textLen - i) < seq.length) { if ((textLen - i) < seq.length) {
continue checkEscapes; continue;
} }
for (j=1; j<seq.length; j++) { for (j=1; j<seq.length; j++) {
@ -92,9 +93,6 @@ abstract class CharsetRecog_2022 extends CharsetRecognizer {
return quality; return quality;
} }
static class CharsetRecog_2022JP extends CharsetRecog_2022 { static class CharsetRecog_2022JP extends CharsetRecog_2022 {
private byte [] [] escapeSequences = { private byte [] [] escapeSequences = {
{0x1b, 0x24, 0x28, 0x43}, // KS X 1001:1992 {0x1b, 0x24, 0x28, 0x43}, // KS X 1001:1992

View file

@ -1,14 +1,15 @@
/** /*
******************************************************************************* *******************************************************************************
* Copyright (C) 2005 - 2014, International Business Machines Corporation and * * Copyright (C) 2005 - 2012, International Business Machines Corporation and *
* others. All Rights Reserved. * * others. All Rights Reserved. *
******************************************************************************* *******************************************************************************
*/ */
package com.ibm.icu.text; package com.ibm.icu.text;
/** /**
* Charset recognizer for UTF-8 * Charset recognizer for UTF-8
*/ */
@SuppressWarnings("ALL")
class CharsetRecog_UTF8 extends CharsetRecognizer { class CharsetRecog_UTF8 extends CharsetRecognizer {
String getName() { String getName() {
@ -24,7 +25,7 @@ class CharsetRecog_UTF8 extends CharsetRecognizer {
int numInvalid = 0; int numInvalid = 0;
byte input[] = det.fRawInput; byte input[] = det.fRawInput;
int i; int i;
int trailBytes = 0; int trailBytes;
int confidence; int confidence;
if (det.fRawLength >= 3 && if (det.fRawLength >= 3 &&

View file

@ -12,6 +12,7 @@ package com.ibm.icu.text;
* This class matches UTF-16 and UTF-32, both big- and little-endian. The * This class matches UTF-16 and UTF-32, both big- and little-endian. The
* BOM will be used if it is present. * BOM will be used if it is present.
*/ */
@SuppressWarnings("ALL")
abstract class CharsetRecog_Unicode extends CharsetRecognizer { abstract class CharsetRecog_Unicode extends CharsetRecognizer {
/* (non-Javadoc) /* (non-Javadoc)
@ -171,7 +172,7 @@ abstract class CharsetRecog_Unicode extends CharsetRecognizer {
{ {
int getChar(byte[] input, int index) int getChar(byte[] input, int index)
{ {
return (input[index + 0] & 0xFF) << 24 | (input[index + 1] & 0xFF) << 16 | return (input[index] & 0xFF) << 24 | (input[index + 1] & 0xFF) << 16 |
(input[index + 2] & 0xFF) << 8 | (input[index + 3] & 0xFF); (input[index + 2] & 0xFF) << 8 | (input[index + 3] & 0xFF);
} }
@ -187,7 +188,7 @@ abstract class CharsetRecog_Unicode extends CharsetRecognizer {
int getChar(byte[] input, int index) int getChar(byte[] input, int index)
{ {
return (input[index + 3] & 0xFF) << 24 | (input[index + 2] & 0xFF) << 16 | return (input[index + 3] & 0xFF) << 24 | (input[index + 2] & 0xFF) << 16 |
(input[index + 1] & 0xFF) << 8 | (input[index + 0] & 0xFF); (input[index + 1] & 0xFF) << 8 | (input[index] & 0xFF);
} }
String getName() String getName()

View file

@ -1,9 +1,8 @@
/* /*
**************************************************************************** *******************************************************************************
* Copyright (C) 2005-2012, International Business Machines Corporation and * * Copyright (C) 2005 - 2012, International Business Machines Corporation and *
* others. All Rights Reserved. * * others. All Rights Reserved. *
**************************************************************************** *******************************************************************************
*
*/ */
package com.ibm.icu.text; package com.ibm.icu.text;
@ -21,6 +20,7 @@ import java.util.Arrays;
* encodings to be checked. The specific encoding being recognized * encodings to be checked. The specific encoding being recognized
* is determined by subclass. * is determined by subclass.
*/ */
@SuppressWarnings("ALL")
abstract class CharsetRecog_mbcs extends CharsetRecognizer { abstract class CharsetRecog_mbcs extends CharsetRecognizer {
/** /**
@ -157,8 +157,7 @@ abstract class CharsetRecog_mbcs extends CharsetRecognizer {
done = true; done = true;
return -1; return -1;
} }
int byteValue = (int)det.fRawInput[nextIndex++] & 0x00ff; return (int)det.fRawInput[nextIndex++] & 0x00ff;
return byteValue;
} }
} }
@ -321,9 +320,9 @@ abstract class CharsetRecog_mbcs extends CharsetRecognizer {
boolean nextChar(iteratedChar it, CharsetDetector det) { boolean nextChar(iteratedChar it, CharsetDetector det) {
it.index = it.nextIndex; it.index = it.nextIndex;
it.error = false; it.error = false;
int firstByte = 0; int firstByte;
int secondByte = 0; int secondByte;
int thirdByte = 0; int thirdByte;
//int fourthByte = 0; //int fourthByte = 0;
buildChar: { buildChar: {
@ -372,7 +371,7 @@ abstract class CharsetRecog_mbcs extends CharsetRecognizer {
} }
} }
return (it.done == false); return (!it.done);
} }
/** /**
@ -461,10 +460,10 @@ abstract class CharsetRecog_mbcs extends CharsetRecognizer {
boolean nextChar(iteratedChar it, CharsetDetector det) { boolean nextChar(iteratedChar it, CharsetDetector det) {
it.index = it.nextIndex; it.index = it.nextIndex;
it.error = false; it.error = false;
int firstByte = 0; int firstByte;
int secondByte = 0; int secondByte;
int thirdByte = 0; int thirdByte;
int fourthByte = 0; int fourthByte;
buildChar: { buildChar: {
firstByte = it.charValue = it.nextByte(det); firstByte = it.charValue = it.nextByte(det);
@ -483,7 +482,7 @@ abstract class CharsetRecog_mbcs extends CharsetRecognizer {
secondByte = it.nextByte(det); secondByte = it.nextByte(det);
it.charValue = (it.charValue << 8) | secondByte; it.charValue = (it.charValue << 8) | secondByte;
if (firstByte >= 0x81 && firstByte <= 0xFE) { if (firstByte <= 0xFE) {
// Two byte Char // Two byte Char
if ((secondByte >= 0x40 && secondByte <= 0x7E) || (secondByte >=80 && secondByte <=0xFE)) { if ((secondByte >= 0x40 && secondByte <= 0x7E) || (secondByte >=80 && secondByte <=0xFE)) {
break buildChar; break buildChar;
@ -504,11 +503,10 @@ abstract class CharsetRecog_mbcs extends CharsetRecognizer {
} }
it.error = true; it.error = true;
break buildChar;
} }
} }
return (it.done == false); return !it.done;
} }
static int [] commonChars = static int [] commonChars =

View file

@ -1,17 +1,16 @@
/* /*
**************************************************************************** *******************************************************************************
* Copyright (C) 2005-2013, International Business Machines Corporation and * * Copyright (C) 2005 - 2012, International Business Machines Corporation and *
* others. All Rights Reserved. * * others. All Rights Reserved. *
************************************************************************** * *******************************************************************************
*
*/ */
package com.ibm.icu.text; package com.ibm.icu.text;
/** /**
* This class recognizes single-byte encodings. Because the encoding scheme is so * This class recognizes single-byte encodings. Because the encoding scheme is so
* simple, language statistics are used to do the matching. * simple, language statistics are used to do the matching.
*/ */
@SuppressWarnings("ALL")
abstract class CharsetRecog_sbcs extends CharsetRecognizer { abstract class CharsetRecog_sbcs extends CharsetRecognizer {
/* (non-Javadoc) /* (non-Javadoc)
@ -25,7 +24,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
private static final int N_GRAM_MASK = 0xFFFFFF; private static final int N_GRAM_MASK = 0xFFFFFF;
protected int byteIndex = 0; protected int byteIndex = 0;
private int ngram = 0; private int ngram;
private int[] ngramList; private int[] ngramList;
protected byte[] byteMap; protected byte[] byteMap;
@ -273,7 +272,7 @@ abstract class CharsetRecog_sbcs extends CharsetRecognizer {
return parser.parse(det, spaceChar); return parser.parse(det, spaceChar);
} }
int matchIBM420(CharsetDetector det, int[] ngrams, byte[] byteMap, byte spaceChar){ int matchIBM420(CharsetDetector det, int[] ngrams, byte[] byteMap, @SuppressWarnings("SameParameterValue") byte spaceChar){
NGramParser_IBM420 parser = new NGramParser_IBM420(ngrams, byteMap); NGramParser_IBM420 parser = new NGramParser_IBM420(ngrams, byteMap);
return parser.parse(det, spaceChar); return parser.parse(det, spaceChar);
} }

View file

@ -1,9 +1,9 @@
/** /*
******************************************************************************* *******************************************************************************
* Copyright (C) 2005-2012, International Business Machines Corporation and * * Copyright (C) 2005 - 2012, International Business Machines Corporation and *
* others. All Rights Reserved. * * others. All Rights Reserved. *
******************************************************************************* *******************************************************************************
*/ */
package com.ibm.icu.text; package com.ibm.icu.text;
/** /**
@ -20,6 +20,7 @@ package com.ibm.icu.text;
* The WILL be shared by multiple instances of CharsetDetector. * The WILL be shared by multiple instances of CharsetDetector.
* They encapsulate const charset-specific information. * They encapsulate const charset-specific information.
*/ */
@SuppressWarnings("ALL")
abstract class CharsetRecognizer { abstract class CharsetRecognizer {
/** /**
* Get the IANA name of this charset. * Get the IANA name of this charset.

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid package org.ligi.passandroid
import android.app.Application import android.app.Application
import android.support.v7.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import com.github.salomonbrys.kodein.* import com.github.salomonbrys.kodein.*
import com.jakewharton.threetenabp.AndroidThreeTen import com.jakewharton.threetenabp.AndroidThreeTen
import com.squareup.leakcanary.LeakCanary import com.squareup.leakcanary.LeakCanary

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid; package org.ligi.passandroid;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
public interface Tracker { public interface Tracker {
void trackException(String s, Throwable e, boolean fatal); void trackException(String s, Throwable e, boolean fatal);

View file

@ -3,15 +3,15 @@ package org.ligi.passandroid.functions
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.provider.CalendarContract import android.provider.CalendarContract
import android.support.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import android.support.design.widget.Snackbar import com.google.android.material.snackbar.Snackbar
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.view.View import android.view.View
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.pass.Pass import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.model.pass.PassImpl import org.ligi.passandroid.model.pass.PassImpl
val DEFAULT_EVENT_LENGTH_IN_HOURS = 8L const val DEFAULT_EVENT_LENGTH_IN_HOURS = 8L
fun tryAddDateToCalendar(pass: Pass, contextView: View, timeSpan: PassImpl.TimeSpan) { fun tryAddDateToCalendar(pass: Pass, contextView: View, timeSpan: PassImpl.TimeSpan) {
if (pass.calendarTimespan == null) { if (pass.calendarTimespan == null) {

View file

@ -33,26 +33,26 @@ fun generateBarCodeBitmap(data: String, type: PassBarCodeFormat): Bitmap? {
// create buffered image to draw to // create buffered image to draw to
// NTFS Bitmap.Config.ALPHA_8 sounds like an awesome idea - been there - done that .. // NTFS Bitmap.Config.ALPHA_8 sounds like an awesome idea - been there - done that ..
val barcode_image = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) val barcodeImage = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565)
// iterate through the matrix and draw the pixels to the image // iterate through the matrix and draw the pixels to the image
for (y in 0..height - 1) { for (y in 0 until height) {
for (x in 0..width - 1) { for (x in 0 until width) {
barcode_image.setPixel(x, y, if (matrix.get(x, if (is1D) 0 else y)) 0 else 0xFFFFFF) barcodeImage.setPixel(x, y, if (matrix.get(x, if (is1D) 0 else y)) 0 else 0xFFFFFF)
} }
} }
return barcode_image return barcodeImage
} catch (e: com.google.zxing.WriterException) { } catch (e: com.google.zxing.WriterException) {
Log.w("could not write image " + e) Log.w("could not write image: $e")
// TODO check if we should better return some rescue Image here // TODO check if we should better return some rescue Image here
return null return null
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
Log.w("could not write image " + e) Log.w("could not write image: $e")
return null return null
} catch (e: ArrayIndexOutOfBoundsException) { } catch (e: ArrayIndexOutOfBoundsException) {
// happens for ITF barcode on certain inputs // happens for ITF barcode on certain inputs
Log.w("could not write image " + e) Log.w("could not write image: $e")
return null return null
} }

View file

@ -1,9 +1,9 @@
package org.ligi.passandroid.functions package org.ligi.passandroid.functions
import android.graphics.Color import android.graphics.Color
import android.support.annotation.ColorInt import androidx.annotation.ColorInt
import android.support.annotation.DrawableRes import androidx.annotation.DrawableRes
import android.support.annotation.StringRes import androidx.annotation.StringRes
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.pass.PassType import org.ligi.passandroid.model.pass.PassType

View file

@ -9,7 +9,7 @@ import org.ligi.passandroid.model.InputStreamWithSource
import java.io.BufferedInputStream import java.io.BufferedInputStream
import java.net.URL import java.net.URL
val IPHONE_USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53" const val IPHONE_USER_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53"
fun fromURI(context: Context, uri: Uri): InputStreamWithSource? { fun fromURI(context: Context, uri: Uri): InputStreamWithSource? {
App.tracker.trackEvent("protocol", "to_inputstream", uri.scheme, null) App.tracker.trackEvent("protocol", "to_inputstream", uri.scheme, null)

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.functions package org.ligi.passandroid.functions
import android.app.Activity import android.app.Activity
import android.support.design.widget.Snackbar import com.google.android.material.snackbar.Snackbar
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.PassClassifier import org.ligi.passandroid.model.PassClassifier
import org.ligi.passandroid.model.pass.Pass import org.ligi.passandroid.model.pass.Pass
@ -9,7 +9,7 @@ import org.ligi.passandroid.model.pass.Pass
fun moveWithUndoSnackbar(passClassifier: PassClassifier, pass: Pass, topic: String, activity: Activity) { fun moveWithUndoSnackbar(passClassifier: PassClassifier, pass: Pass, topic: String, activity: Activity) {
val oldTopic = passClassifier.getTopic(pass, "") val oldTopic = passClassifier.getTopic(pass, "")
Snackbar.make(activity.window.decorView.findViewById(R.id.fam), "Pass moved to " + topic, Snackbar.LENGTH_LONG) Snackbar.make(activity.window.decorView.findViewById(R.id.fam), "Pass moved to $topic", Snackbar.LENGTH_LONG)
.setAction(R.string.undo) { passClassifier.moveToTopic(pass, oldTopic) } .setAction(R.string.undo) { passClassifier.moveToTopic(pass, oldTopic) }
.show() .show()
passClassifier.moveToTopic(pass, topic) passClassifier.moveToTopic(pass, topic)

View file

@ -15,7 +15,7 @@ import java.io.FileNotFoundException
import java.io.FileOutputStream import java.io.FileOutputStream
import java.util.* import java.util.*
val APP = "passandroid" const val APP = "passandroid"
fun createAndAddEmptyPass(passStore: PassStore, resources: Resources): Pass { fun createAndAddEmptyPass(passStore: PassStore, resources: Resources): Pass {
val pass = createBasePass() val pass = createBasePass()

View file

@ -40,7 +40,7 @@ class AndroidFileSystemPassStore(private val context: Context, settings: Setting
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
val of = com.squareup.moshi.JsonWriter.of(buffer) val of = com.squareup.moshi.JsonWriter.of(buffer)
of.setIndent(" ") of.indent = " "
jsonAdapter.toJson(of, pass as PassImpl) jsonAdapter.toJson(of, pass as PassImpl)
buffer.close() buffer.close()
of.close() of.close()
@ -86,7 +86,7 @@ class AndroidFileSystemPassStore(private val context: Context, settings: Setting
if (dirty) { if (dirty) {
save(result) save(result)
} }
passMap.put(id, result) passMap[id] = result
notifyChange() notifyChange()
} }

View file

@ -2,7 +2,7 @@ package org.ligi.passandroid.model
import android.content.Context import android.content.Context
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.v7.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.R.string.preference_key_autolight import org.ligi.passandroid.R.string.preference_key_autolight
import org.ligi.passandroid.R.string.preference_key_condensed import org.ligi.passandroid.R.string.preference_key_condensed
@ -11,12 +11,12 @@ import java.io.File
class AndroidSettings(val context: Context) : Settings { class AndroidSettings(val context: Context) : Settings {
internal val sharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(context) } private val sharedPreferences by lazy { PreferenceManager.getDefaultSharedPreferences(context) }
override fun getSortOrder(): PassSortOrder { override fun getSortOrder(): PassSortOrder {
val key = context.getString(R.string.preference_key_sort) val key = context.getString(R.string.preference_key_sort)
val stringValue = sharedPreferences.getString(key, "0") val stringValue = sharedPreferences.getString(key, "0")
val id = Integer.valueOf(stringValue)!! val id = Integer.valueOf(stringValue!!)
return PassSortOrder.values().first { it.int == id } return PassSortOrder.values().first { it.int == id }
} }

View file

@ -24,7 +24,7 @@ class ApplePassbookQuirkCorrector(val tracker: Tracker) {
tryToFindDate(pass) tryToFindDate(pass)
} }
fun tryToFindDate(pass: PassImpl) { private fun tryToFindDate(pass: PassImpl) {
if (pass.calendarTimespan == null) { if (pass.calendarTimespan == null) {
val foundDate = pass.fields.filter { "date" == it.key }.map { val foundDate = pass.fields.filter { "date" == it.key }.map {
@ -44,11 +44,11 @@ class ApplePassbookQuirkCorrector(val tracker: Tracker) {
} }
private fun getPassFieldForKey(pass: PassImpl, key: String): PassField? { private fun getPassFieldForKey(pass: PassImpl, key: String): PassField? {
return pass.fields.firstOrNull() { it.key != null && it.key == key } return pass.fields.firstOrNull { it.key != null && it.key == key }
} }
private fun getPassFieldThatMatchesLabel(pass: PassImpl, matcher: String): PassField? { private fun getPassFieldThatMatchesLabel(pass: PassImpl, matcher: String): PassField? {
return pass.fields.firstOrNull() { return pass.fields.firstOrNull {
val label = it.label val label = it.label
label != null && label.matches(matcher.toRegex()) label != null && label.matches(matcher.toRegex())
} }

View file

@ -1,8 +1,8 @@
package org.ligi.passandroid.model; package org.ligi.passandroid.model;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import com.ibm.icu.text.CharsetDetector; import com.ibm.icu.text.CharsetDetector;
import com.ibm.icu.text.CharsetMatch; import com.ibm.icu.text.CharsetMatch;
import java.io.DataInputStream; import java.io.DataInputStream;
@ -12,7 +12,6 @@ import java.io.UnsupportedEncodingException;
import java.util.HashMap; import java.util.HashMap;
import org.ligi.passandroid.App; import org.ligi.passandroid.App;
@VisibleForTesting
public class AppleStylePassTranslation extends HashMap<String, String> { public class AppleStylePassTranslation extends HashMap<String, String> {
public String translate(String key) { public String translate(String key) {
@ -63,6 +62,7 @@ public class AppleStylePassTranslation extends HashMap<String, String> {
if (fileData[0] == (byte) 0xEF && fileData[1] == (byte) 0xBB && fileData[2] == (byte) 0xBF) { if (fileData[0] == (byte) 0xEF && fileData[1] == (byte) 0xBB && fileData[2] == (byte) 0xBF) {
final byte[] crop = new byte[fileData.length - 3]; final byte[] crop = new byte[fileData.length - 3];
System.arraycopy(fileData, 3, crop, 0, crop.length); System.arraycopy(fileData, 3, crop, 0, crop.length);
//noinspection CharsetObjectCanBeUsed
return new String(crop, "utf-8"); return new String(crop, "utf-8");
} }

View file

@ -14,7 +14,7 @@ open class PassClassifier(val topicByIdMap: MutableMap<String, String>, private
} }
fun moveToTopic(pass: Pass, newTopic: String) { fun moveToTopic(pass: Pass, newTopic: String) {
topicByIdMap.put(pass.id, newTopic) topicByIdMap[pass.id] = newTopic
processDataChange() processDataChange()
} }
@ -24,7 +24,7 @@ open class PassClassifier(val topicByIdMap: MutableMap<String, String>, private
} }
fun getPassListByTopic(topic: String): List<Pass> { fun getPassListByTopic(topic: String): List<Pass> {
return topicByIdMap.filter { it.value.equals(topic) }.map { passStore.getPassbookForId(it.key) }.filterNotNull() return topicByIdMap.filter { it.value == topic }.map { passStore.getPassbookForId(it.key) }.filterNotNull()
} }
fun getTopic(pass: Pass, default: String): String { fun getTopic(pass: Pass, default: String): String {
@ -38,7 +38,7 @@ open class PassClassifier(val topicByIdMap: MutableMap<String, String>, private
} }
if (!default.isEmpty()) { if (!default.isEmpty()) {
topicByIdMap.put(id, default) topicByIdMap[id] = default
processDataChange() processDataChange()
} }
return default return default

View file

@ -4,7 +4,7 @@ import org.ligi.passandroid.model.comparator.PassSortOrder
import org.ligi.passandroid.model.pass.Pass import org.ligi.passandroid.model.pass.Pass
import java.util.* import java.util.*
class PassStoreProjection(private val passStore: PassStore, val topic: String, private val passSortOrder: PassSortOrder? = null) { class PassStoreProjection(private val passStore: PassStore, private val topic: String, private val passSortOrder: PassSortOrder? = null) {
var passList: List<Pass> = ArrayList() var passList: List<Pass> = ArrayList()
private set private set

View file

@ -1,18 +1,12 @@
package org.ligi.passandroid.model package org.ligi.passandroid.model
import android.annotation.TargetApi
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Build
import org.ligi.passandroid.Tracker import org.ligi.passandroid.Tracker
import java.util.* import java.util.*
class PastLocationsStore constructor(private val sharedPreferences: SharedPreferences, private val tracker: Tracker) { class PastLocationsStore constructor(private val sharedPreferences: SharedPreferences, private val tracker: Tracker) {
fun putLocation(path: String) { fun putLocation(path: String) {
if (Build.VERSION.SDK_INT < 11) {
// feature not available for these versions
return
}
val pastLocations = sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, HashSet<String>()) val pastLocations = sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, HashSet<String>())
if (pastLocations!!.size >= MAX_ELEMENTS) { if (pastLocations!!.size >= MAX_ELEMENTS) {
@ -39,17 +33,11 @@ class PastLocationsStore constructor(private val sharedPreferences: SharedPrefer
// feature not available for these versions // feature not available for these versions
val locations: Set<String> val locations: Set<String>
@TargetApi(11) get() = sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, emptySet<String>())
get() {
if (Build.VERSION.SDK_INT < 11) {
return HashSet()
}
return sharedPreferences.getStringSet(KEY_PAST_LOCATIONS, HashSet<String>())
}
companion object { companion object {
val KEY_PAST_LOCATIONS = "past_locations" const val KEY_PAST_LOCATIONS = "past_locations"
val MAX_ELEMENTS = 5 const val MAX_ELEMENTS = 5
} }
} }

View file

@ -9,7 +9,7 @@ class DirectionAwarePassByTimeComparator(private val direction: Int) : PassByTim
} }
companion object { companion object {
val DIRECTION_DESC = -1 const val DIRECTION_DESC = -1
val DIRECTION_ASC = 1 const val DIRECTION_ASC = 1
} }
} }

View file

@ -7,9 +7,9 @@ import java.util.*
open class PassByTimeComparator : Comparator<Pass> { open class PassByTimeComparator : Comparator<Pass> {
override fun compare(lhs: Pass, rhs: Pass): Int { override fun compare(lhs: Pass, rhs: Pass): Int {
return calculateCompareForNullValues(lhs, rhs, { leftDate: ZonedDateTime, rightDate: ZonedDateTime -> return calculateCompareForNullValues(lhs, rhs) { leftDate: ZonedDateTime, rightDate: ZonedDateTime ->
return@calculateCompareForNullValues leftDate.compareTo(rightDate) return@calculateCompareForNullValues leftDate.compareTo(rightDate)
}) }
} }
protected fun calculateCompareForNullValues(lhs: Pass, rhs: Pass, foo: (leftDate: ZonedDateTime, rightDate: ZonedDateTime) -> Int): Int { protected fun calculateCompareForNullValues(lhs: Pass, rhs: Pass, foo: (leftDate: ZonedDateTime, rightDate: ZonedDateTime) -> Int): Int {

View file

@ -11,10 +11,10 @@ class PassByTypeFirstAndTimeSecondComparator : Comparator<Pass> {
override fun compare(lhs: Pass, rhs: Pass): Int { override fun compare(lhs: Pass, rhs: Pass): Int {
val compareResult = lhs.type.compareTo(rhs.type) val compareResult = lhs.type.compareTo(rhs.type)
if (compareResult != 0) { return if (compareResult != 0) {
return compareResult compareResult
} else { } else {
return passByTimeComparator.compare(lhs, rhs) passByTimeComparator.compare(lhs, rhs)
} }
} }
} }

View file

@ -9,12 +9,10 @@ enum class PassSortOrder constructor(val int: Int) {
TYPE(1), TYPE(1),
DATE_DIFF(2); DATE_DIFF(2);
fun toComparator(): Comparator<Pass> { fun toComparator(): Comparator<Pass> = when (this) {
when (this) { TYPE -> PassByTypeFirstAndTimeSecondComparator()
TYPE -> return PassByTypeFirstAndTimeSecondComparator() DATE_DESC -> DirectionAwarePassByTimeComparator(DirectionAwarePassByTimeComparator.DIRECTION_DESC)
DATE_DESC -> return DirectionAwarePassByTimeComparator(DirectionAwarePassByTimeComparator.DIRECTION_DESC) DATE_DIFF -> PassTemporalDistanceComparator()
DATE_DIFF -> return PassTemporalDistanceComparator() DATE_ASC -> DirectionAwarePassByTimeComparator(DirectionAwarePassByTimeComparator.DIRECTION_ASC)
DATE_ASC -> return DirectionAwarePassByTimeComparator(DirectionAwarePassByTimeComparator.DIRECTION_ASC)
}
} }
} }

View file

@ -8,11 +8,11 @@ import org.threeten.bp.ZonedDateTime
class PassTemporalDistanceComparator : PassByTimeComparator() { class PassTemporalDistanceComparator : PassByTimeComparator() {
override fun compare(lhs: Pass, rhs: Pass): Int { override fun compare(lhs: Pass, rhs: Pass): Int {
return calculateCompareForNullValues(lhs, rhs, { leftDate: ZonedDateTime, rightDate: ZonedDateTime -> return calculateCompareForNullValues(lhs, rhs) { leftDate: ZonedDateTime, rightDate: ZonedDateTime ->
val durationLeft = Duration.between(LocalDateTime.now(), leftDate).abs() val durationLeft = Duration.between(LocalDateTime.now(), leftDate).abs()
val durationRight = Duration.between(LocalDateTime.now(), rightDate).abs() val durationRight = Duration.between(LocalDateTime.now(), rightDate).abs()
return@calculateCompareForNullValues durationLeft.compareTo(durationRight) return@calculateCompareForNullValues durationLeft.compareTo(durationRight)
}) }
} }
} }

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.model.pass package org.ligi.passandroid.model.pass
import android.graphics.Bitmap import android.graphics.Bitmap
import android.support.annotation.StringDef import androidx.annotation.StringDef
import org.ligi.passandroid.model.PassBitmapDefinitions.* import org.ligi.passandroid.model.PassBitmapDefinitions.*
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.model.pass package org.ligi.passandroid.model.pass
import android.content.res.Resources import android.content.res.Resources
import android.support.annotation.StringRes import androidx.annotation.StringRes
class PassField(var key: String?, var label: String?, var value: String?, var hide: Boolean) { class PassField(var key: String?, var label: String?, var value: String?, var hide: Boolean) {

View file

@ -59,13 +59,13 @@ class PassImpl(override val id: String) : Pass {
override var passIdent: String? = null override var passIdent: String? = null
override fun getBitmap(passStore: PassStore, @Pass.PassBitmap passBitmap: String): Bitmap? { override fun getBitmap(passStore: PassStore, @Pass.PassBitmap passBitmap: String): Bitmap? {
try { return try {
val file = File(passStore.getPathForID(id), passBitmap + FILETYPE_IMAGES) val file = File(passStore.getPathForID(id), passBitmap + FILETYPE_IMAGES)
return BitmapFactory.decodeStream(FileInputStream(file)) BitmapFactory.decodeStream(FileInputStream(file))
} catch (expectedInSomeCases_willJustReturnNull: FileNotFoundException) { } catch (expectedInSomeCases_willJustReturnNull: FileNotFoundException) {
return null null
} catch (e: OutOfMemoryError) { } catch (e: OutOfMemoryError) {
return null null
} }
} }
@ -84,7 +84,7 @@ class PassImpl(override val id: String) : Pass {
} }
companion object { companion object {
val FILETYPE_IMAGES = ".png" const val FILETYPE_IMAGES = ".png"
} }
} }

View file

@ -69,7 +69,7 @@ class PassPrintDocumentAdapter(private val context: Context, private val pass: P
val centerPaint = Paint() val centerPaint = Paint()
centerPaint.textAlign = Paint.Align.CENTER centerPaint.textAlign = Paint.Align.CENTER
canvas.drawText(pass.description, canvas.width / 2f, centerPaint.textSize, centerPaint) canvas.drawText(pass.description!!, canvas.width / 2f, centerPaint.textSize, centerPaint)
var currentBottom = centerPaint.textSize * 3 var currentBottom = centerPaint.textSize * 3
val barCode = pass.barCode val barCode = pass.barCode
@ -83,14 +83,14 @@ class PassPrintDocumentAdapter(private val context: Context, private val pass: P
val destRect = Rect(0, 0, (bitmap.width * ratio).toInt(), (bitmap.height * ratio).toInt()) val destRect = Rect(0, 0, (bitmap.width * ratio).toInt(), (bitmap.height * ratio).toInt())
destRect.offset(((canvas.width - destRect.width()) / 2).toInt(), currentBottom.toInt()) destRect.offset((canvas.width - destRect.width()) / 2, currentBottom.toInt())
currentBottom += destRect.bottom currentBottom += destRect.bottom
canvas.drawBitmap(bitmap, srcRect, destRect, centerPaint) canvas.drawBitmap(bitmap, srcRect, destRect, centerPaint)
if (barCode.alternativeText != null) { if (barCode.alternativeText != null) {
canvas.drawText(barCode.alternativeText, destRect.centerX().toFloat(), destRect.bottom.toFloat() + 7 + centerPaint.textSize, centerPaint) canvas.drawText(barCode.alternativeText!!, destRect.centerX().toFloat(), destRect.bottom.toFloat() + 7 + centerPaint.textSize, centerPaint)
currentBottom += 7 + centerPaint.textSize * 2 currentBottom += 7 + centerPaint.textSize * 2
} }
} }

View file

@ -32,76 +32,76 @@ object AppleStylePassReader {
val pass = PassImpl(passFile.name) val pass = PassImpl(passFile.name)
var pass_json: JSONObject? = null var passJSON: JSONObject? = null
val localized_path = findLocalizedPath(passFile, language) val localizedPath = findLocalizedPath(passFile, language)
if (localized_path != null) { if (localizedPath != null) {
val file = File(localized_path, "pass.strings") val file = File(localizedPath, "pass.strings")
translation.loadFromFile(file) translation.loadFromFile(file)
} }
copyBitmapFile(passFile, localized_path, PassBitmapDefinitions.BITMAP_ICON) copyBitmapFile(passFile, localizedPath, PassBitmapDefinitions.BITMAP_ICON)
copyBitmapFile(passFile, localized_path, PassBitmapDefinitions.BITMAP_LOGO) copyBitmapFile(passFile, localizedPath, PassBitmapDefinitions.BITMAP_LOGO)
copyBitmapFile(passFile, localized_path, PassBitmapDefinitions.BITMAP_STRIP) copyBitmapFile(passFile, localizedPath, PassBitmapDefinitions.BITMAP_STRIP)
copyBitmapFile(passFile, localized_path, PassBitmapDefinitions.BITMAP_THUMBNAIL) copyBitmapFile(passFile, localizedPath, PassBitmapDefinitions.BITMAP_THUMBNAIL)
copyBitmapFile(passFile, localized_path, PassBitmapDefinitions.BITMAP_FOOTER) copyBitmapFile(passFile, localizedPath, PassBitmapDefinitions.BITMAP_FOOTER)
val file = File(passFile, "pass.json") val file = File(passFile, "pass.json")
try { try {
val plainJsonString = AppleStylePassTranslation.readFileAsStringGuessEncoding(file) val plainJsonString = AppleStylePassTranslation.readFileAsStringGuessEncoding(file)
pass_json = readJSONSafely(plainJsonString) passJSON = readJSONSafely(plainJsonString)
} catch (e: Exception) { } catch (e: Exception) {
Log.i("PassParse Exception " + e) Log.i("PassParse Exception: $e")
} }
if (pass_json == null) { if (passJSON == null) {
// I had got a strange passbook with UCS-2 which could not be parsed before // I had got a strange passbook with UCS-2 which could not be parsed before
// was searching for a auto-detection, but could not find one with support for this encoding // was searching for a auto-detection, but could not find one with support for this encoding
// and the right license // and the right license
for (charset in Charset.availableCharsets().values) { for (charset in Charset.availableCharsets().values) {
try { try {
val json_str = file.bufferedReader(charset).readText() val json = file.bufferedReader(charset).readText()
pass_json = readJSONSafely(json_str) passJSON = readJSONSafely(json)
} catch (ignored: Exception) { } catch (ignored: Exception) {
// we try with next charset // we try with next charset
} }
if (pass_json != null) { if (passJSON != null) {
break break
} }
} }
} }
if (pass_json == null) { if (passJSON == null) {
Log.w("could not load pass.json from passcode ") Log.w("could not load pass.json from passcode ")
App.tracker.trackEvent("problem_event", "pass", "without_pass_json", null) App.tracker.trackEvent("problem_event", "pass", "without_pass_json", null)
return null return null
} }
try { try {
val barcode_json = pass_json.getBarcodeJson() val barcodeJSON = passJSON.getBarcodeJson()
if (barcode_json != null) { if (barcodeJSON != null) {
val barcodeFormatString = barcode_json.getString("format") val barcodeFormatString = barcodeJSON.getString("format")
App.tracker.trackEvent("measure_event", "barcode_format", barcodeFormatString, 0L) App.tracker.trackEvent("measure_event", "barcode_format", barcodeFormatString, 0L)
val barcodeFormat = BarCode.getFormatFromString(barcodeFormatString) val barcodeFormat = BarCode.getFormatFromString(barcodeFormatString)
val barCode = BarCode(barcodeFormat, barcode_json.getString("message")) val barCode = BarCode(barcodeFormat, barcodeJSON.getString("message"))
pass.barCode = barCode pass.barCode = barCode
if (barcode_json.has("altText")) { if (barcodeJSON.has("altText")) {
pass.barCode!!.alternativeText = barcode_json.getString("altText") pass.barCode!!.alternativeText = barcodeJSON.getString("altText")
} }
} }
// TODO should check a bit more with barcode here - this can be dangerous // TODO should check a bit more with barcode here - this can be dangerous
} catch (ignored: Exception) { } catch (ignored: Exception) {
} }
if (pass_json.has("relevantDate")) { if (passJSON.has("relevantDate")) {
try { try {
pass.calendarTimespan = PassImpl.TimeSpan(from = ZonedDateTime.parse(pass_json.getString("relevantDate"))) pass.calendarTimespan = PassImpl.TimeSpan(from = ZonedDateTime.parse(passJSON.getString("relevantDate")))
} catch (e: JSONException) { } catch (e: JSONException) {
// be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here // be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here
// OK then we just have no date here // OK then we just have no date here
@ -112,9 +112,9 @@ object AppleStylePassReader {
} }
if (pass_json.has("expirationDate")) { if (passJSON.has("expirationDate")) {
try { try {
pass.validTimespans = listOf(PassImpl.TimeSpan(to = ZonedDateTime.parse(pass_json.getString("expirationDate")))) pass.validTimespans = listOf(PassImpl.TimeSpan(to = ZonedDateTime.parse(passJSON.getString("expirationDate"))))
} catch (e: JSONException) { } catch (e: JSONException) {
// be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here // be robust when it comes to bad dates - had a RL crash with "2013-12-25T00:00-57:00" here
// OK then we just have no date here // OK then we just have no date here
@ -125,17 +125,17 @@ object AppleStylePassReader {
} }
pass.serial = readJsonSafeAsOptional(pass_json, "serialNumber") pass.serial = readJsonSafeAsOptional(passJSON, "serialNumber")
pass.authToken = readJsonSafeAsOptional(pass_json, "authenticationToken") pass.authToken = readJsonSafeAsOptional(passJSON, "authenticationToken")
pass.webServiceURL = readJsonSafeAsOptional(pass_json, "webServiceURL") pass.webServiceURL = readJsonSafeAsOptional(passJSON, "webServiceURL")
pass.passIdent = readJsonSafeAsOptional(pass_json, "passTypeIdentifier") pass.passIdent = readJsonSafeAsOptional(passJSON, "passTypeIdentifier")
val locations = ArrayList<PassLocation>() val locations = ArrayList<PassLocation>()
try { try {
val locations_json = pass_json.getJSONArray("locations") val locationsJSON = passJSON.getJSONArray("locations")
for (i in 0..locations_json.length() - 1) { for (i in 0 until locationsJSON.length()) {
val obj = locations_json.getJSONObject(i) val obj = locationsJSON.getJSONObject(i)
val location = PassLocation() val location = PassLocation()
location.lat = obj.getDouble("latitude") location.lat = obj.getDouble("latitude")
@ -153,13 +153,13 @@ object AppleStylePassReader {
pass.locations = locations pass.locations = locations
readJsonSafe(pass_json, "backgroundColor", object : JsonStringReadCallback { readJsonSafe(passJSON, "backgroundColor", object : JsonStringReadCallback {
override fun onString(string: String) { override fun onString(string: String) {
pass.accentColor = string.parseColor(Color.BLACK) pass.accentColor = string.parseColor(Color.BLACK)
} }
}) })
readJsonSafe(pass_json, "description", object : JsonStringReadCallback { readJsonSafe(passJSON, "description", object : JsonStringReadCallback {
override fun onString(string: String) { override fun onString(string: String) {
pass.description = translation.translate(string) pass.description = translation.translate(string)
} }
@ -169,22 +169,22 @@ object AppleStylePassReader {
// try to find in a predefined set of tickets // try to find in a predefined set of tickets
PassDefinitions.TYPE_TO_NAME.forEach { PassDefinitions.TYPE_TO_NAME.forEach {
if (pass_json!!.has(it.value)) { if (passJSON.has(it.value)) {
pass.type = it.key pass.type = it.key
} }
} }
try { try {
val type = PassDefinitions.TYPE_TO_NAME[pass.type] val type = PassDefinitions.TYPE_TO_NAME[pass.type]
val type_json = pass_json.getJSONObject(type) val typeJSON = passJSON.getJSONObject(type)
if (type_json != null) { if (typeJSON != null) {
val fieldList: ArrayList<PassField> = ArrayList() val fieldList: ArrayList<PassField> = ArrayList()
addFields(fieldList, type_json, "primaryFields", translation) addFields(fieldList, typeJSON, "primaryFields", translation)
addFields(fieldList, type_json, "headerFields", translation) addFields(fieldList, typeJSON, "headerFields", translation)
addFields(fieldList, type_json, "secondaryFields", translation) addFields(fieldList, typeJSON, "secondaryFields", translation)
addFields(fieldList, type_json, "auxiliaryFields", translation) addFields(fieldList, typeJSON, "auxiliaryFields", translation)
addFields(fieldList, type_json, "backFields", translation, hide = true) addFields(fieldList, typeJSON, "backFields", translation, hide = true)
fieldList.add(PassField("", context.getString(R.string.type), context.getString(getHumanCategoryString(pass.type)), false)) fieldList.add(PassField("", context.getString(R.string.type), context.getString(getHumanCategoryString(pass.type)), false))
pass.fields = fieldList pass.fields = fieldList
@ -195,7 +195,7 @@ object AppleStylePassReader {
try { try {
pass.creator = pass_json.getString("organizationName") pass.creator = passJSON.getString("organizationName")
App.tracker.trackEvent("measure_event", "organisation_parse", pass.creator, 1L) App.tracker.trackEvent("measure_event", "organisation_parse", pass.creator, 1L)
} catch (ignored: JSONException) { } catch (ignored: JSONException) {
// ok - we have no organisation - big deal ..-) // ok - we have no organisation - big deal ..-)
@ -220,7 +220,7 @@ object AppleStylePassReader {
private fun addFields(list: ArrayList<PassField>, type_json: JSONObject, fieldsName: String, translation: AppleStylePassTranslation, hide: Boolean = false) { private fun addFields(list: ArrayList<PassField>, type_json: JSONObject, fieldsName: String, translation: AppleStylePassTranslation, hide: Boolean = false) {
try { try {
val jsonArray = type_json.getJSONArray(fieldsName) val jsonArray = type_json.getJSONArray(fieldsName)
for (i in 0..jsonArray.length() - 1) { for (i in 0 until jsonArray.length()) {
try { try {
val jsonObject = jsonArray.getJSONObject(i) val jsonObject = jsonArray.getJSONObject(i)
val field = PassField(key = getField(jsonObject, "key", translation), val field = PassField(key = getField(jsonObject, "key", translation),
@ -230,19 +230,18 @@ object AppleStylePassReader {
list.add(field) list.add(field)
} catch (e: JSONException) { } catch (e: JSONException) {
Log.w("could not process PassField from JSON for $fieldsName cause:$e") Log.w("could not process PassField from JSON for $fieldsName cause: $e")
} }
} }
} catch (e: JSONException) { } catch (e: JSONException) {
Log.w("could not process PassFields $fieldsName from JSON$e") Log.w("could not process PassFields $fieldsName from JSON: $e")
} }
} }
private fun findLocalizedPath(path: File, language: String): String? { private fun findLocalizedPath(path: File, language: String): String? {
val localized = File(path, "$language.lproj")
val localized = File(path, language + ".lproj")
if (localized.exists() && localized.isDirectory) { if (localized.exists() && localized.isDirectory) {
App.tracker.trackEvent("measure_event", "pass", language + "_native_lproj", null) App.tracker.trackEvent("measure_event", "pass", language + "_native_lproj", null)
@ -282,7 +281,6 @@ object AppleStylePassReader {
} catch (e: JSONException) { } catch (e: JSONException) {
// some passes just do not have the field // some passes just do not have the field
} }
} }
} }
@ -294,7 +292,6 @@ object AppleStylePassReader {
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
} }
} }
@ -329,6 +326,4 @@ object AppleStylePassReader {
} }
return null return null
} }
} }

View file

@ -21,47 +21,47 @@ object PassReader {
try { try {
val plainJsonString = file.bufferedReader().readText() val plainJsonString = file.bufferedReader().readText()
val pass_json = readJSONSafely(plainJsonString)!! val passJSON = readJSONSafely(plainJsonString)!!
if (pass_json.has("what")) { if (passJSON.has("what")) {
val what_json = pass_json.getJSONObject("what") val whatJSON = passJSON.getJSONObject("what")
pass.description = what_json.getString("description") pass.description = whatJSON.getString("description")
} }
if (pass_json.has("meta")) { if (passJSON.has("meta")) {
val meta_json = pass_json.getJSONObject("meta") val metaJSON = passJSON.getJSONObject("meta")
pass.type = PassDefinitions.NAME_TO_TYPE[meta_json.getString("type")] ?: PassType.GENERIC pass.type = PassDefinitions.NAME_TO_TYPE[metaJSON.getString("type")] ?: PassType.GENERIC
pass.creator = meta_json.getString("organisation") pass.creator = metaJSON.getString("organisation")
pass.app = meta_json.getString("app") pass.app = metaJSON.getString("app")
} }
if (pass_json.has("ui")) { if (passJSON.has("ui")) {
val ui_json = pass_json.getJSONObject("ui") val uiJSON = passJSON.getJSONObject("ui")
pass.accentColor = Color.parseColor(ui_json.getString("bgColor")) pass.accentColor = Color.parseColor(uiJSON.getString("bgColor"))
} }
if (pass_json.has("barcode")) { if (passJSON.has("barcode")) {
val barcode_json = pass_json.getJSONObject("barcode") val barcodeJSON = passJSON.getJSONObject("barcode")
val barcodeFormatString = barcode_json.getString("type") val barcodeFormatString = barcodeJSON.getString("type")
val barcodeFormat = BarCode.getFormatFromString(barcodeFormatString) val barcodeFormat = BarCode.getFormatFromString(barcodeFormatString)
val barCode = BarCode(barcodeFormat, barcode_json.getString("message")) val barCode = BarCode(barcodeFormat, barcodeJSON.getString("message"))
pass.barCode = barCode pass.barCode = barCode
if (barcode_json.has("altText")) { if (barcodeJSON.has("altText")) {
barCode.alternativeText = barcode_json.getString("altText") barCode.alternativeText = barcodeJSON.getString("altText")
} }
} }
if (pass_json.has("when")) { if (passJSON.has("when")) {
val dateTime = pass_json.getJSONObject("when").getString("dateTime") val dateTime = passJSON.getJSONObject("when").getString("dateTime")
pass.calendarTimespan = PassImpl.TimeSpan() pass.calendarTimespan = PassImpl.TimeSpan()
pass.calendarTimespan = PassImpl.TimeSpan(from = ZonedDateTime.parse(dateTime)) pass.calendarTimespan = PassImpl.TimeSpan(from = ZonedDateTime.parse(dateTime))
} }
} catch (e: Exception) { } catch (e: Exception) {
Log.i("PassParse Exception " + e) Log.i("PassParse Exception: $e")
} }
return pass return pass

View file

@ -4,14 +4,15 @@ import android.app.Activity
import android.view.View import android.view.View
import android.view.View.* import android.view.View.*
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout import android.widget.LinearLayout
import kotlinx.android.synthetic.main.barcode.view.* import kotlinx.android.synthetic.main.barcode.view.*
import org.ligi.kaxt.getSmallestSide import org.ligi.kaxt.getSmallestSide
import org.ligi.passandroid.model.pass.BarCode import org.ligi.passandroid.model.pass.BarCode
internal class BarcodeUIController(val rootView: View, private val barCode: BarCode?, activity: Activity, private val passViewHelper: PassViewHelper) { internal class BarcodeUIController(private val rootView: View, private val barCode: BarCode?, activity: Activity, private val passViewHelper: PassViewHelper) {
fun getBarcodeView() = rootView.barcode_img fun getBarcodeView(): ImageView = rootView.barcode_img
private var currentBarcodeWidth: Int = 0 private var currentBarcodeWidth: Int = 0

View file

@ -22,11 +22,13 @@ class ExtractURLAsIphoneActivity : PassAndroidActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (intent?.data != null) {
progressDialog.show() progressDialog.show()
tracker.trackEvent("quirk_fix", "unpack_attempt", intent.data.host, null) tracker.trackEvent("quirk_fix", "unpack_attempt", intent?.data?.host, null)
DownloadExtractAndStartImportTask().execute() DownloadExtractAndStartImportTask().execute()
} }
}
private inner class DownloadExtractAndStartImportTask : AsyncTask<Void, Void, String>() { private inner class DownloadExtractAndStartImportTask : AsyncTask<Void, Void, String>() {
@ -34,7 +36,7 @@ class ExtractURLAsIphoneActivity : PassAndroidActivity() {
val client = OkHttpClient() val client = OkHttpClient()
try { try {
val requestBuilder = Request.Builder().url(URI(intent.data.toString()).toURL()) val requestBuilder = Request.Builder().url(URI(intent?.data.toString()).toURL())
requestBuilder.header("User-Agent", IPHONE_USER_AGENT) requestBuilder.header("User-Agent", IPHONE_USER_AGENT)
val body = client.newCall(requestBuilder.build()).execute().body() val body = client.newCall(requestBuilder.build()).execute().body()
@ -46,7 +48,7 @@ class ExtractURLAsIphoneActivity : PassAndroidActivity() {
val url = extractURL(bodyString) ?: return null val url = extractURL(bodyString) ?: return null
if (!url.startsWith("http")) { if (!url.startsWith("http")) {
return intent.data.scheme + "://" + intent.data.host + "/" + url return intent?.data?.scheme + "://" + intent?.data?.host + "/" + url
} }
return url return url
@ -79,7 +81,7 @@ class ExtractURLAsIphoneActivity : PassAndroidActivity() {
return return
} }
tracker.trackEvent("quirk_fix", "unpack_success", intent.data.host, null) tracker.trackEvent("quirk_fix", "unpack_success", intent?.data?.host, null)
val intent = Intent(this@ExtractURLAsIphoneActivity, PassImportActivity::class.java) val intent = Intent(this@ExtractURLAsIphoneActivity, PassImportActivity::class.java)
intent.data = Uri.parse(s) intent.data = Uri.parse(s)

View file

@ -2,6 +2,7 @@ package org.ligi.passandroid.ui
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
@ -15,12 +16,19 @@ class FullscreenBarcodeActivity : PassViewActivityBase() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.fullscreen_image) setContentView(R.layout.fullscreen_image)
if (Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
}
} }
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
if (currentPass == null || currentPass.barCode == null) { if (currentPass.barCode == null) {
Log.w("FullscreenBarcodeActivity in bad state") Log.w("FullscreenBarcodeActivity in bad state")
finish() // this should never happen, but better safe than sorry finish() // this should never happen, but better safe than sorry
return return
@ -47,7 +55,6 @@ class FullscreenBarcodeActivity : PassViewActivityBase() {
* ( reverse orientation / sensor is the problem here ..) * ( reverse orientation / sensor is the problem here ..)
*/ */
private fun setBestFittingOrientationForBarCode() { private fun setBestFittingOrientationForBarCode() {
if (currentPass.barCode!!.format!!.isQuadratic()) { if (currentPass.barCode!!.format!!.isQuadratic()) {
when (requestedOrientation) { when (requestedOrientation) {
@ -72,9 +79,4 @@ class FullscreenBarcodeActivity : PassViewActivityBase() {
} }
} }
override fun onAttachedToWindow() {
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
}
} }

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.text.Editable import android.text.Editable
import android.text.Html import android.text.Html
import android.text.method.LinkMovementMethod import android.text.method.LinkMovementMethod

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.app.Activity import android.app.Activity
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
@ -26,9 +26,10 @@ internal class MoveToNewTopicUI(private val context: Activity, private val passS
dialog.dismiss() dialog.dismiss()
} }
val newTopicEditText = dialog.findViewById(R.id.new_topic_edit) as EditText val newTopicEditText = dialog.findViewById<EditText>(R.id.new_topic_edit)
val suggestionButtonContainer= dialog.findViewById(R.id.topic_suggestions_button_container) as ViewGroup val suggestionButtonContainer = dialog.findViewById<ViewGroup>(R.id.topic_suggestions_button_container)
if (newTopicEditText != null) {
// we need to do this here so the dialog does not get dismissed // we need to do this here so the dialog does not get dismissed
dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener { dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
if (newTopicEditText.text.toString().isEmpty()) { if (newTopicEditText.text.toString().isEmpty()) {
@ -38,17 +39,18 @@ internal class MoveToNewTopicUI(private val context: Activity, private val passS
move(newTopicEditText.text.toString()) move(newTopicEditText.text.toString())
} }
} }
}
val oldTopic = passStore.classifier.getTopic(pass, "") val oldTopic = passStore.classifier.getTopic(pass, "")
val suggestionTopicStringIds = intArrayOf(R.string.topic_trash, R.string.topic_archive, R.string.topic_new) val suggestionTopicStringIds = intArrayOf(R.string.topic_trash, R.string.topic_archive, R.string.topic_new)
suggestionTopicStringIds.map { context.getString(it) }.forEach { suggestionTopicStringIds.map { context.getString(it) }.forEach { topic ->
if (it != oldTopic) { if (topic != oldTopic) {
val button = Button(context) val button = Button(context)
button.text = it button.text = topic
suggestionButtonContainer.addView(button) suggestionButtonContainer?.addView(button)
button.setOnClickListener { _ -> move(it) } button.setOnClickListener { move(topic) }
} }
} }
} }

View file

@ -2,32 +2,36 @@ package org.ligi.passandroid.ui;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.support.design.widget.AppBarLayout; import com.google.android.material.appbar.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar; import androidx.annotation.NonNull;
import android.support.v4.view.ViewCompat; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.snackbar.Snackbar;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import net.i2p.android.ext.floatingactionbutton.FloatingActionsMenu; import net.i2p.android.ext.floatingactionbutton.FloatingActionsMenu;
import org.ligi.passandroid.R; import org.ligi.passandroid.R;
@SuppressWarnings("WeakerAccess")
public class MyShyFABBehavior extends CoordinatorLayout.Behavior<FloatingActionsMenu> { public class MyShyFABBehavior extends CoordinatorLayout.Behavior<FloatingActionsMenu> {
public MyShyFABBehavior() { public MyShyFABBehavior() {}
}
public MyShyFABBehavior(Context context, AttributeSet attrs) { public MyShyFABBehavior(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
} }
@Override @Override
public boolean layoutDependsOn(CoordinatorLayout parent, FloatingActionsMenu child, View dependency) { public boolean layoutDependsOn(@NonNull CoordinatorLayout parent,
@NonNull FloatingActionsMenu child,
@NonNull View dependency) {
return dependency instanceof Snackbar.SnackbarLayout || dependency instanceof AppBarLayout; return dependency instanceof Snackbar.SnackbarLayout || dependency instanceof AppBarLayout;
} }
@Override @Override
public boolean onDependentViewChanged(CoordinatorLayout parent, FloatingActionsMenu child, View dependency) { public boolean onDependentViewChanged(@NonNull CoordinatorLayout parent,
@NonNull FloatingActionsMenu child,
@NonNull View dependency) {
if (dependency instanceof Snackbar.SnackbarLayout) { if (dependency instanceof Snackbar.SnackbarLayout) {
updateFabTranslationForSnackbar(child, dependency); updateFabTranslationForSnackbar(child, dependency);
} }
@ -40,23 +44,24 @@ public class MyShyFABBehavior extends CoordinatorLayout.Behavior<FloatingActions
} else { } else {
distanceToScroll = (int) (child.getContext().getResources().getDimension(R.dimen.fab_size_normal) + 2 * fabBottomMargin); distanceToScroll = (int) (child.getContext().getResources().getDimension(R.dimen.fab_size_normal) + 2 * fabBottomMargin);
} }
final float ratio = ViewCompat.getY(dependency) / getToolbarHeight(dependency.getContext()); final float ratio = dependency.getY() / getToolbarHeight(dependency.getContext());
ViewCompat.setTranslationY(child, -distanceToScroll * ratio); child.setTranslationY(-distanceToScroll * ratio);
} }
return false; return false;
} }
@Override @Override
public void onDependentViewRemoved(final CoordinatorLayout parent, final FloatingActionsMenu child, final View dependency) { public void onDependentViewRemoved(@NonNull final CoordinatorLayout parent,
@NonNull final FloatingActionsMenu child,
@NonNull final View dependency) {
super.onDependentViewRemoved(parent, child, dependency); super.onDependentViewRemoved(parent, child, dependency);
onDependentViewChanged(parent,child,dependency); onDependentViewChanged(parent,child,dependency);
} }
private void updateFabTranslationForSnackbar(FloatingActionsMenu child, View dependency) { private void updateFabTranslationForSnackbar(FloatingActionsMenu child, View dependency) {
final float translationY = ViewCompat.getTranslationY(dependency) - dependency.getHeight(); final float translationY = dependency.getTranslationY() - dependency.getHeight();
final float translationYClipped = Math.min(0, translationY); child.setTranslationY(Math.min(0, translationY));
ViewCompat.setTranslationY(child, translationYClipped);
} }
private int getToolbarHeight(Context context) { private int getToolbarHeight(Context context) {

View file

@ -4,7 +4,7 @@ import android.app.Activity
import android.content.ActivityNotFoundException import android.content.ActivityNotFoundException
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.pass.Pass import org.ligi.passandroid.model.pass.Pass
import org.ligi.passandroid.model.pass.PassLocation import org.ligi.passandroid.model.pass.PassLocation
@ -15,12 +15,13 @@ import java.net.URLEncoder
fun Activity.showNavigateToLocationsDialog(pass: Pass, finishOnDone: Boolean) { fun Activity.showNavigateToLocationsDialog(pass: Pass, finishOnDone: Boolean) {
val locations = pass.locations val locations = pass.locations
if (locations.isEmpty()) { when {
done(this, finishOnDone) locations.isEmpty() -> done(this, finishOnDone)
} else if (locations.size == 1) { locations.size == 1 -> {
startIntentForLocation(this, locations.first(), pass) startIntentForLocation(this, locations.first(), pass)
done(this, finishOnDone) done(this, finishOnDone)
} else if (locations.size > 1) { }
locations.size > 1 -> {
val locationDescriptions = arrayOfNulls<String>(locations.size) val locationDescriptions = arrayOfNulls<String>(locations.size)
var i = 0 var i = 0
@ -33,7 +34,7 @@ fun Activity.showNavigateToLocationsDialog(pass: Pass, finishOnDone: Boolean) {
done(this, finishOnDone) done(this, finishOnDone)
} }
.show() .show()
}
} }
} }

View file

@ -1,9 +1,9 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.support.design.widget.Snackbar import com.google.android.material.snackbar.Snackbar
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.support.v7.widget.CardView import androidx.cardview.widget.CardView
import android.support.v7.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.ViewGroup import android.view.ViewGroup
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
@ -26,12 +26,11 @@ class PassAdapter(private val passListActivity: AppCompatActivity, private val p
val inflater = LayoutInflater.from(viewGroup.context) val inflater = LayoutInflater.from(viewGroup.context)
val res = inflater.inflate(R.layout.pass_list_item, viewGroup, false) as CardView val res = inflater.inflate(R.layout.pass_list_item, viewGroup, false) as CardView
if (settings.isCondensedModeEnabled()) { return if (settings.isCondensedModeEnabled()) {
return CondensedPassViewHolder(res) CondensedPassViewHolder(res)
} else { } else {
return VerbosePassViewHolder(res) VerbosePassViewHolder(res)
} }
} }
override fun onBindViewHolder(viewHolder: PassViewHolder, position: Int) { override fun onBindViewHolder(viewHolder: PassViewHolder, position: Int) {

View file

@ -1,9 +1,8 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.ligi.kaxt.recreateWhenPossible
import org.ligi.passandroid.App import org.ligi.passandroid.App
import org.ligi.passandroid.Tracker import org.ligi.passandroid.Tracker
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore
@ -22,7 +21,7 @@ open class PassAndroidActivity : AppCompatActivity() {
super.onResume() super.onResume()
if (lastSetNightMode != null && lastSetNightMode != settings.getNightMode()) { if (lastSetNightMode != null && lastSetNightMode != settings.getNightMode()) {
recreateWhenPossible() recreate()
} }
lastSetNightMode = settings.getNightMode() lastSetNightMode = settings.getNightMode()
} }

View file

@ -3,11 +3,12 @@ package org.ligi.passandroid.ui
import android.Manifest import android.Manifest
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.annotation.IdRes import androidx.annotation.IdRes
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.widget.Button
import android.widget.ImageView import android.widget.ImageView
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import kotlinx.android.synthetic.main.edit.* import kotlinx.android.synthetic.main.edit.*
@ -58,7 +59,7 @@ class PassEditActivity : AppCompatActivity() {
when (i) { when (i) {
0 -> showCategoryPickDialog(this@PassEditActivity, currentPass, bus) 0 -> showCategoryPickDialog(this@PassEditActivity, currentPass, bus)
1 -> showColorPickDialog(this@PassEditActivity, currentPass, bus) 1 -> showColorPickDialog(this@PassEditActivity, currentPass, bus)
2 -> PassEditActivityPermissionsDispatcher.pickImageWithCheck(this@PassEditActivity, ImageEditHelper.REQ_CODE_PICK_ICON) 2 -> pickImageWithPermissionCheck(ImageEditHelper.REQ_CODE_PICK_ICON)
} }
}.show() }.show()
} }
@ -103,7 +104,7 @@ class PassEditActivity : AppCompatActivity() {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
PassEditActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults) onRequestPermissionsResult(requestCode, grantResults)
} }
private fun refresh(pass: Pass) { private fun refresh(pass: Pass) {
@ -126,14 +127,14 @@ class PassEditActivity : AppCompatActivity() {
val bitmap = currentPass.getBitmap(passStore, imageString) val bitmap = currentPass.getBitmap(passStore, imageString)
val addButton = findViewById(add_logo)!! val addButton = findViewById<Button>(add_logo)!!
addButton.visibility = if (bitmap == null) View.VISIBLE else View.GONE addButton.visibility = if (bitmap == null) View.VISIBLE else View.GONE
val listener = View.OnClickListener { val listener = View.OnClickListener {
PassEditActivityPermissionsDispatcher.pickImageWithCheck(this@PassEditActivity, requestCode) pickImageWithPermissionCheck(requestCode)
} }
val logoImage = findViewById(logo_img) as ImageView val logoImage = findViewById<ImageView>(logo_img)
passViewHelper.setBitmapSafe(logoImage, bitmap) passViewHelper.setBitmapSafe(logoImage, bitmap)
logoImage.setOnClickListener(listener) logoImage.setOnClickListener(listener)
addButton.setOnClickListener(listener) addButton.setOnClickListener(listener)
@ -159,7 +160,5 @@ class PassEditActivity : AppCompatActivity() {
true true
} }
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
} }

View file

@ -4,35 +4,35 @@ import android.app.Activity
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.Intent import android.content.Intent
import android.os.Handler import android.os.Handler
import android.support.annotation.UiThread import androidx.annotation.UiThread
import android.support.v4.content.FileProvider import androidx.core.content.FileProvider
import android.widget.Toast import android.widget.Toast
import org.ligi.passandroid.App import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import java.io.File import java.io.File
internal open class PassExportTaskAndShare(protected val activity: Activity, val inputPath: File) { internal open class PassExportTaskAndShare(protected val activity: Activity, private val inputPath: File) {
@UiThread @UiThread
fun execute() { fun execute() {
val file = File(activity.filesDir, "share/share.espass") // important - the FileProvider must be configured for this path val file = File(activity.filesDir, "share/share.espass") // important - the FileProvider must be configured for this path
val passExporter = PassExporter(inputPath, file) val passExporter = PassExporter(inputPath, file)
val progress_dialog = ProgressDialog(activity) val progressDialog = ProgressDialog(activity)
progress_dialog.setTitle(R.string.preparing_pass) progressDialog.setTitle(R.string.preparing_pass)
progress_dialog.setMessage(activity.getString(R.string.please_wait)) progressDialog.setMessage(activity.getString(R.string.please_wait))
progress_dialog.show() progressDialog.show()
val handler = Handler() val handler = Handler()
Thread(Runnable { Thread(Runnable {
passExporter.export() passExporter.export()
handler.post { handler.post {
if (!activity.isFinishing && progress_dialog.isShowing) { if (!activity.isFinishing && progressDialog.isShowing) {
progress_dialog.dismiss() progressDialog.dismiss()
} }
if (passExporter.exception != null) { if (passExporter.exception != null) {
App.tracker.trackException("passExporterException", passExporter.exception, false) App.tracker.trackException("passExporterException", passExporter.exception!!, false)
Toast.makeText(activity, "could not export pass " + passExporter.exception, Toast.LENGTH_LONG).show() Toast.makeText(activity, "could not export pass: " + passExporter.exception, Toast.LENGTH_LONG).show()
} else { } else {
val uriForFile = FileProvider.getUriForFile(activity, activity.getString(R.string.authority_fileprovider), file) val uriForFile = FileProvider.getUriForFile(activity, activity.getString(R.string.authority_fileprovider), file)
val it = Intent(Intent.ACTION_SEND) val it = Intent(Intent.ACTION_SEND)

View file

@ -2,9 +2,8 @@ package org.ligi.passandroid.ui
import android.Manifest import android.Manifest
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.DialogInterface
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import org.ligi.kaxt.dismissIfShowing import org.ligi.kaxt.dismissIfShowing
import org.ligi.kaxt.startActivityFromClass import org.ligi.kaxt.startActivityFromClass
@ -44,22 +43,21 @@ class PassImportActivity : AppCompatActivity() {
progressDialog.show() progressDialog.show()
doImport(false) doImportWithPermissionCheck(false)
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
PassImportActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults) onRequestPermissionsResult(requestCode, grantResults)
} }
@NeedsPermission(Manifest.permission.READ_EXTERNAL_STORAGE) @NeedsPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
fun doImport(withPermission: Boolean) { fun doImport(withPermission: Boolean) {
Thread({ Thread {
try { try {
val fromURI = fromURI(this, intent.data) val fromURI = fromURI(this, intent!!.data!!)
runOnUiThread({ runOnUiThread {
progressDialog.dismissIfShowing() progressDialog.dismissIfShowing()
if (fromURI == null) { if (fromURI == null) {
@ -87,25 +85,20 @@ class PassImportActivity : AppCompatActivity() {
} }
} }
} }
}) }
} catch (e: Exception) { } catch (e: Exception) {
if (e.message?.contains("Permission") == true && !withPermission) { if (e.message?.contains("Permission") == true && !withPermission) {
PassImportActivityPermissionsDispatcher.doImportWithCheck(this@PassImportActivity, true) doImportWithPermissionCheck(true)
} else { } else {
tracker.trackException("Error in import", e, false) tracker.trackException("Error in import", e, false)
} }
} }
}.start()
}).start()
} }
@OnPermissionDenied(Manifest.permission.READ_EXTERNAL_STORAGE) @OnPermissionDenied(Manifest.permission.READ_EXTERNAL_STORAGE)
fun showDeniedDialog() { fun showDeniedDialog() {
progressDialog.dismissIfShowing() progressDialog.dismissIfShowing()
alert(R.string.error_no_permission_msg, R.string.error_no_permission_title, onOKListener = DialogInterface.OnClickListener { _, _ -> finish() }) alert(R.string.error_no_permission_msg, R.string.error_no_permission_title, onOK = { finish() })
} }
} }

View file

@ -10,11 +10,11 @@ import android.content.Intent
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.Snackbar import com.google.android.material.snackbar.Snackbar
import android.support.v4.view.GravityCompat import androidx.core.view.GravityCompat
import android.support.v4.view.ViewPager import androidx.viewpager.widget.ViewPager
import android.support.v7.app.ActionBarDrawerToggle import androidx.appcompat.app.ActionBarDrawerToggle
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
@ -99,7 +99,7 @@ class PassListActivity : PassAndroidActivity() {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
PassListActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults) onRequestPermissionsResult(requestCode, grantResults)
} }
@TargetApi(VERSION_STARTING_TO_SUPPORT_STORAGE_FRAMEWORK) @TargetApi(VERSION_STARTING_TO_SUPPORT_STORAGE_FRAMEWORK)
@ -162,7 +162,7 @@ class PassListActivity : PassAndroidActivity() {
override fun onPageSelected(position: Int) { override fun onPageSelected(position: Int) {
State.lastSelectedTab = position State.lastSelectedTab = position
supportInvalidateOptionsMenu() invalidateOptionsMenu()
} }
override fun onPageScrollStateChanged(state: Int) { override fun onPageScrollStateChanged(state: Int) {
@ -189,7 +189,7 @@ class PassListActivity : PassAndroidActivity() {
} }
fab_action_scan.setOnClickListener { fab_action_scan.setOnClickListener {
PassListActivityPermissionsDispatcher.scanWithCheck(this) scanWithPermissionCheck()
fam.collapse() fam.collapse()
} }
@ -214,7 +214,11 @@ class PassListActivity : PassAndroidActivity() {
} }
R.id.menu_emptytrash -> { R.id.menu_emptytrash -> {
AlertDialog.Builder(this).setMessage(getString(R.string.empty_trash_dialog_message)).setIcon(R.drawable.ic_alert_warning).setTitle(getString(R.string.empty_trash_dialog_title)).setPositiveButton(R.string.emtytrash_label) { dialog, which -> AlertDialog.Builder(this)
.setMessage(getString(R.string.empty_trash_dialog_message))
.setIcon(R.drawable.ic_alert_warning)
.setTitle(getString(R.string.empty_trash_dialog_title))
.setPositiveButton(R.string.emtytrash_label) { _, _ ->
val passStoreProjection = PassStoreProjection(passStore, val passStoreProjection = PassStoreProjection(passStore,
getString(R.string.topic_trash), getString(R.string.topic_trash),
null) null)
@ -225,7 +229,6 @@ class PassListActivity : PassAndroidActivity() {
}.setNegativeButton(android.R.string.cancel, null).show() }.setNegativeButton(android.R.string.cancel, null).show()
true true
} }
else -> drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item) else -> drawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item)
} }
@ -269,7 +272,7 @@ class PassListActivity : PassAndroidActivity() {
setupWithViewPagerIfNeeded() setupWithViewPagerIfNeeded()
supportInvalidateOptionsMenu() invalidateOptionsMenu()
val empty = passStore.classifier.topicByIdMap.isEmpty() val empty = passStore.classifier.topicByIdMap.isEmpty()
emptyView.visibility = if (empty) View.VISIBLE else View.GONE emptyView.visibility = if (empty) View.VISIBLE else View.GONE
@ -284,7 +287,6 @@ class PassListActivity : PassAndroidActivity() {
} }
private fun areTabLayoutAndViewPagerInSync(): Boolean { private fun areTabLayoutAndViewPagerInSync(): Boolean {
if (adapter.count != tab_layout.tabCount) { if (adapter.count != tab_layout.tabCount) {
return false return false
} }
@ -296,7 +298,6 @@ class PassListActivity : PassAndroidActivity() {
} }
} }
return true return true
} }
override fun onBackPressed() { override fun onBackPressed() {
@ -306,5 +307,4 @@ class PassListActivity : PassAndroidActivity() {
else -> super.onBackPressed() else -> super.onBackPressed()
} }
} }
} }

View file

@ -1,13 +1,14 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.os.Bundle import android.os.Bundle
import android.support.annotation.VisibleForTesting import androidx.annotation.VisibleForTesting
import android.support.v4.app.Fragment import androidx.fragment.app.Fragment
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.support.v7.widget.helper.ItemTouchHelper import androidx.recyclerview.widget.RecyclerView.ViewHolder
import android.support.v7.widget.helper.ItemTouchHelper.* import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.ItemTouchHelper.*
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -38,7 +39,7 @@ class PassListFragment : Fragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val inflate = inflater.inflate(R.layout.pass_recycler, container, false) val inflate = inflater.inflate(R.layout.pass_recycler, container, false)
passStoreProjection = PassStoreProjection(passStore, arguments.getString(BUNDLE_KEY_TOPIC)!!, settings.getSortOrder()) passStoreProjection = PassStoreProjection(passStore, arguments?.getString(BUNDLE_KEY_TOPIC)!!, settings.getSortOrder())
adapter = PassAdapter(activity as AppCompatActivity, passStoreProjection) adapter = PassAdapter(activity as AppCompatActivity, passStoreProjection)
inflate.pass_recyclerview.adapter = adapter inflate.pass_recyclerview.adapter = adapter
@ -47,10 +48,10 @@ class PassListFragment : Fragment() {
val simpleItemTouchCallback = object : SimpleCallback(0, LEFT or RIGHT) { val simpleItemTouchCallback = object : SimpleCallback(0, LEFT or RIGHT) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder) override fun onMove(recyclerView: RecyclerView, viewHolder: ViewHolder, target: ViewHolder)
= false = false
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) { override fun onSwiped(viewHolder: ViewHolder, swipeDir: Int) {
this@PassListFragment.onSwiped(viewHolder.adapterPosition, swipeDir) this@PassListFragment.onSwiped(viewHolder.adapterPosition, swipeDir)
} }
} }
@ -67,10 +68,12 @@ class PassListFragment : Fragment() {
val pass = passStoreProjection.passList[pos] val pass = passStoreProjection.passList[pos]
val nextTopic = passStore.classifier.getTopicWithOffset(pass, if (swipeDir == LEFT) -1 else 1) val nextTopic = passStore.classifier.getTopicWithOffset(pass, if (swipeDir == LEFT) -1 else 1)
activity?.let {
if (nextTopic != null) { if (nextTopic != null) {
moveWithUndoSnackbar(passStore.classifier, pass, nextTopic, activity) moveWithUndoSnackbar(passStore.classifier, pass, nextTopic, it)
} else { } else {
MoveToNewTopicUI(activity, passStore, pass).show() MoveToNewTopicUI(it, passStore, pass).show()
}
} }
} }
@ -93,12 +96,12 @@ class PassListFragment : Fragment() {
} }
companion object { companion object {
private const val BUNDLE_KEY_TOPIC = "topic"
private val BUNDLE_KEY_TOPIC = "topic"
fun newInstance(topic: String) = PassListFragment().apply { fun newInstance(topic: String) = PassListFragment().apply {
arguments = Bundle() val bundle = Bundle()
arguments.putString(BUNDLE_KEY_TOPIC, topic) bundle.putString(BUNDLE_KEY_TOPIC, topic)
arguments = bundle
} }
} }

View file

@ -2,8 +2,8 @@ package org.ligi.passandroid.ui
import android.app.Activity import android.app.Activity
import android.content.Intent import android.content.Intent
import android.support.v4.app.NavUtils import androidx.core.app.NavUtils
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.MenuItem import android.view.MenuItem
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance

View file

@ -1,9 +1,10 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.support.design.widget.NavigationView import com.google.android.material.navigation.NavigationView
import android.util.AttributeSet import android.util.AttributeSet
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import kotlinx.android.synthetic.main.navigation_drawer_header.view.* import kotlinx.android.synthetic.main.navigation_drawer_header.view.*
@ -20,9 +21,8 @@ class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView
val passStore: PassStore = App.kodein.instance() val passStore: PassStore = App.kodein.instance()
val bus: EventBus = App.kodein.instance() val bus: EventBus = App.kodein.instance()
fun getIntent(id: Int) = when (id) { private fun getIntent(id: Int) = when (id) {
R.id.menu_settings -> Intent(context, PreferenceActivity::class.java) R.id.menu_settings -> Intent(context, PreferenceActivity::class.java)
R.id.menu_plus -> intentFromUrl("https://plus.google.com/communities/116353894782342292067")
R.id.menu_github -> intentFromUrl("https://github.com/ligi/PassAndroid") R.id.menu_github -> intentFromUrl("https://github.com/ligi/PassAndroid")
R.id.menu_beta -> intentFromUrl("https://play.google.com/apps/testing/org.ligi.passandroid") R.id.menu_beta -> intentFromUrl("https://play.google.com/apps/testing/org.ligi.passandroid")
R.id.menu_language -> intentFromUrl("https://transifex.com/projects/p/passandroid") R.id.menu_language -> intentFromUrl("https://transifex.com/projects/p/passandroid")
@ -33,8 +33,9 @@ class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView
else -> null else -> null
} }
fun intentFromUrl(url: String) = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse(url) } private fun intentFromUrl(url: String) = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse(url) }
@SuppressLint("RestrictedApi") // FIXME: temporary workaround for false-positive
override fun onAttachedToWindow() { override fun onAttachedToWindow() {
super.onAttachedToWindow() super.onAttachedToWindow()
@ -50,6 +51,7 @@ class PassNavigationView(context: Context, attrs: AttributeSet) : NavigationView
onPassStoreChangeEvent(PassStoreChangeEvent) onPassStoreChangeEvent(PassStoreChangeEvent)
} }
@SuppressLint("RestrictedApi") // FIXME: temporary workaround for false-positive
override fun onDetachedFromWindow() { override fun onDetachedFromWindow() {
super.onDetachedFromWindow() super.onDetachedFromWindow()
bus.unregister(this) bus.unregister(this)

View file

@ -1,13 +1,13 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.support.v4.app.FragmentManager import androidx.fragment.app.FragmentManager
import android.support.v4.app.FragmentStatePagerAdapter import androidx.fragment.app.FragmentStatePagerAdapter
import android.support.v4.view.PagerAdapter import androidx.viewpager.widget.PagerAdapter
import org.ligi.passandroid.model.PassClassifier import org.ligi.passandroid.model.PassClassifier
class PassTopicFragmentPagerAdapter(private val passClassifier: PassClassifier, fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) { class PassTopicFragmentPagerAdapter(private val passClassifier: PassClassifier, fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
private lateinit var topic_array: Array<String> private lateinit var topics: Array<String>
init { init {
notifyDataSetChanged() notifyDataSetChanged()
@ -15,15 +15,16 @@ class PassTopicFragmentPagerAdapter(private val passClassifier: PassClassifier,
override fun notifyDataSetChanged() { override fun notifyDataSetChanged() {
val topics = passClassifier.getTopics() val topics = passClassifier.getTopics()
topic_array = topics.toTypedArray() this.topics = topics.toTypedArray()
super.notifyDataSetChanged() super.notifyDataSetChanged()
} }
override fun getItem(position: Int) = PassListFragment.newInstance(topic_array[position]) override fun getItem(position: Int) = PassListFragment.newInstance(topics[position])
override fun getItemPosition(`object`: Any?) = PagerAdapter.POSITION_NONE // TODO - return POSITION_UNCHANGED in some cases // TODO - return POSITION_UNCHANGED in some cases
override fun getItemPosition(`object`: Any) = PagerAdapter.POSITION_NONE
override fun getCount() = topic_array.size override fun getCount() = topics.size
override fun getPageTitle(position: Int) = topic_array[position] override fun getPageTitle(position: Int) = topics[position]
} }

View file

@ -2,11 +2,14 @@ package org.ligi.passandroid.ui
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.* import androidx.core.app.*
import android.support.v4.view.ViewPager import androidx.viewpager.widget.ViewPager
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.WindowManager import android.view.WindowManager
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter
import kotlinx.android.synthetic.main.activity_pass_view_base.* import kotlinx.android.synthetic.main.activity_pass_view_base.*
import org.ligi.kaxt.disableRotation import org.ligi.kaxt.disableRotation
import org.ligi.passandroid.R import org.ligi.passandroid.R
@ -20,6 +23,13 @@ class PassViewActivity : PassViewActivityBase() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
this.window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
}
disableRotation() disableRotation()
setContentView(R.layout.activity_pass_view) setContentView(R.layout.activity_pass_view)
@ -30,8 +40,8 @@ class PassViewActivity : PassViewActivityBase() {
viewPager.adapter = pagerAdapter viewPager.adapter = pagerAdapter
viewPager.currentItem = pagerAdapter.getPos(currentPass) viewPager.currentItem = pagerAdapter.getPos(currentPass)
viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() { viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(i: Int) { override fun onPageSelected(pos: Int) {
currentPass = pagerAdapter.getPass(i) currentPass = pagerAdapter.getPass(pos)
passStore.currentPass = currentPass passStore.currentPass = currentPass
} }
}) })
@ -95,6 +105,7 @@ class PassViewActivity : PassViewActivityBase() {
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
android.R.id.home -> { android.R.id.home -> {
val upIntent = NavUtils.getParentActivityIntent(this) val upIntent = NavUtils.getParentActivityIntent(this)
if (upIntent != null) {
if (NavUtils.shouldUpRecreateTask(this, upIntent)) { if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities() TaskStackBuilder.create(this).addNextIntentWithParentStack(upIntent).startActivities()
finish() finish()
@ -103,10 +114,9 @@ class PassViewActivity : PassViewActivityBase() {
} }
true true
} }
else false
}
else -> super.onOptionsItemSelected(item) else -> super.onOptionsItemSelected(item)
} }
override fun onAttachedToWindow() = window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
} }

View file

@ -5,12 +5,15 @@ import android.app.Dialog
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.ComponentName import android.content.ComponentName
import android.content.Intent import android.content.Intent
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.drawable.Icon
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.support.design.widget.Snackbar import com.google.android.material.snackbar.Snackbar
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.view.* import android.view.*
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -25,6 +28,7 @@ import org.ligi.passandroid.ui.UnzipPassController.InputStreamUnzipControllerSpe
import permissions.dispatcher.NeedsPermission import permissions.dispatcher.NeedsPermission
import permissions.dispatcher.RuntimePermissions import permissions.dispatcher.RuntimePermissions
import java.io.IOException import java.io.IOException
import java.util.*
@SuppressLint("Registered") @SuppressLint("Registered")
@RuntimePermissions @RuntimePermissions
@ -44,10 +48,8 @@ open class PassViewActivityBase : PassAndroidActivity() {
try { try {
val config = ViewConfiguration.get(this) val config = ViewConfiguration.get(this)
val menuKeyField = ViewConfiguration::class.java.getDeclaredField("sHasPermanentMenuKey") val menuKeyField = ViewConfiguration::class.java.getDeclaredField("sHasPermanentMenuKey")
if (menuKeyField != null) {
menuKeyField.isAccessible = true menuKeyField.isAccessible = true
menuKeyField.setBoolean(config, false) menuKeyField.setBoolean(config, false)
}
} catch (ex: Exception) { } catch (ex: Exception) {
// Ignore - but at least we tried ;-) // Ignore - but at least we tried ;-)
} }
@ -82,7 +84,7 @@ open class PassViewActivityBase : PassAndroidActivity() {
} }
if (passStore.currentPass == null) { if (passStore.currentPass == null) {
tracker.trackException("pass not present in " + this, false) tracker.trackException("pass not present in $this", false)
finish() finish()
return return
} }
@ -127,7 +129,7 @@ open class PassViewActivityBase : PassAndroidActivity() {
} }
R.id.install_shortcut -> { R.id.install_shortcut -> {
PassViewActivityBasePermissionsDispatcher.createShortcutWithCheck(this) createShortcutWithPermissionCheck()
true true
} }
@ -143,29 +145,40 @@ open class PassViewActivityBase : PassAndroidActivity() {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
PassViewActivityBasePermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults) onRequestPermissionsResult(requestCode, grantResults)
} }
@NeedsPermission("com.android.launcher.permission.INSTALL_SHORTCUT") @NeedsPermission("com.android.launcher.permission.INSTALL_SHORTCUT")
fun createShortcut() { fun createShortcut() {
val intent = Intent("com.android.launcher.action.INSTALL_SHORTCUT")
val shortcutIntent = Intent() val shortcutIntent = Intent()
shortcutIntent.putExtra(EXTRA_KEY_UUID, currentPass.id) shortcutIntent.putExtra(EXTRA_KEY_UUID, currentPass.id)
val component = ComponentName(BuildConfig.APPLICATION_ID, BuildConfig.APPLICATION_ID + ".ui.PassViewActivity") shortcutIntent.component = ComponentName(BuildConfig.APPLICATION_ID,
shortcutIntent.component = component BuildConfig.APPLICATION_ID + ".ui.PassViewActivity")
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent)
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, currentPass.description)
val passBitmap = currentPass.getBitmap(passStore, BITMAP_ICON) val passBitmap = currentPass.getBitmap(passStore, BITMAP_ICON)
val shortcutIcon = if (passBitmap != null) {
val bitmapToUse = if (passBitmap != null) {
Bitmap.createScaledBitmap(passBitmap, 128, 128, true) Bitmap.createScaledBitmap(passBitmap, 128, 128, true)
} else { } else {
BitmapFactory.decodeResource(resources, R.drawable.ic_launcher) BitmapFactory.decodeResource(resources, R.drawable.ic_launcher)
} }
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmapToUse)
if (Build.VERSION.SDK_INT >= 25) {
val shortcutManager = getSystemService<ShortcutManager>(ShortcutManager::class.java)
val shortcut = ShortcutInfo.Builder(this, "id1")
.setShortLabel(currentPass.description ?: "")
.setIcon(Icon.createWithBitmap(shortcutIcon))
.setIntent(shortcutIntent)
.build()
shortcutManager.dynamicShortcuts = Arrays.asList(shortcut)
} else {
val intent = Intent("com.android.launcher.action.INSTALL_SHORTCUT")
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent)
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, currentPass.description)
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, shortcutIcon)
sendBroadcast(intent) sendBroadcast(intent)
} }
}
inner class UpdateAsync : Runnable { inner class UpdateAsync : Runnable {
@ -183,7 +196,7 @@ open class PassViewActivityBase : PassAndroidActivity() {
val url = pass.webServiceURL + "/v1/passes/" + pass.passIdent + "/" + pass.serial val url = pass.webServiceURL + "/v1/passes/" + pass.passIdent + "/" + pass.serial
val requestBuilder = Request.Builder().url(url) val requestBuilder = Request.Builder().url(url)
requestBuilder.addHeader("Authorization", "ApplePass " + pass.authToken!!) requestBuilder.addHeader("Authorization", "ApplePass " + pass.authToken)
val request = requestBuilder.build() val request = requestBuilder.build()
@ -250,7 +263,7 @@ open class PassViewActivityBase : PassAndroidActivity() {
params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL
win.attributes = params win.attributes = params
fullBrightnessSet = true fullBrightnessSet = true
supportInvalidateOptionsMenu() invalidateOptionsMenu()
} }
companion object { companion object {

View file

@ -2,14 +2,15 @@ package org.ligi.passandroid.ui
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.Fragment import androidx.fragment.app.Fragment
import android.support.v4.text.util.LinkifyCompat import androidx.core.text.util.LinkifyCompat
import android.text.util.Linkify import android.text.util.Linkify
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.fragment.app.FragmentActivity
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import kotlinx.android.synthetic.main.activity_pass_view.* import kotlinx.android.synthetic.main.activity_pass_view.*
import kotlinx.android.synthetic.main.barcode.* import kotlinx.android.synthetic.main.barcode.*
@ -27,7 +28,7 @@ import org.ligi.passandroid.ui.pass_view_holder.VerbosePassViewHolder
class PassViewFragment : Fragment() { class PassViewFragment : Fragment() {
private val passViewHelper by lazy { PassViewHelper(activity) } private val passViewHelper by lazy { PassViewHelper(requireActivity()) }
private var passStore : PassStore = App.kodein.instance() private var passStore : PassStore = App.kodein.instance()
lateinit var pass : Pass lateinit var pass : Pass
@ -57,10 +58,10 @@ class PassViewFragment : Fragment() {
} }
barcode_img.setOnClickListener { barcode_img.setOnClickListener {
activity.startActivityFromClass(FullscreenBarcodeActivity::class.java) activity?.startActivityFromClass(FullscreenBarcodeActivity::class.java)
} }
BarcodeUIController(view!!, pass.barCode, activity, passViewHelper) BarcodeUIController(view!!, pass.barCode, activity!!, passViewHelper)
processImage(logo_img_view, PassBitmapDefinitions.BITMAP_LOGO, pass) processImage(logo_img_view, PassBitmapDefinitions.BITMAP_LOGO, pass)
processImage(footer_img_view, PassBitmapDefinitions.BITMAP_FOOTER, pass) processImage(footer_img_view, PassBitmapDefinitions.BITMAP_FOOTER, pass)
@ -68,7 +69,7 @@ class PassViewFragment : Fragment() {
processImage(strip_img_view, PassBitmapDefinitions.BITMAP_STRIP, pass) processImage(strip_img_view, PassBitmapDefinitions.BITMAP_STRIP, pass)
if (map_container != null) { if (map_container != null) {
if (!(pass.locations.isNotEmpty() && PassbookMapsFacade.init(activity))) { if (!(pass.locations.isNotEmpty() && PassbookMapsFacade.init(activity as FragmentActivity))) {
@Suppress("PLUGIN_WARNING") @Suppress("PLUGIN_WARNING")
map_container.visibility = View.GONE map_container.visibility = View.GONE
} }
@ -82,15 +83,15 @@ class PassViewFragment : Fragment() {
if (field.hide) { if (field.hide) {
backStrBuilder.append(field.toHtmlSnippet()) backStrBuilder.append(field.toHtmlSnippet())
} else { } else {
val v = activity.layoutInflater.inflate(R.layout.main_field_item, front_field_container, false) val v = activity!!.layoutInflater.inflate(R.layout.main_field_item, front_field_container, false)
val key = v.findViewById(R.id.key) as TextView val key = v?.findViewById<TextView>(R.id.key)
key.text = field.label key?.text = field.label
val value = v.findViewById(R.id.value) as TextView val value = v?.findViewById<TextView>(R.id.value)
value.text = field.value value?.text = field.value
front_field_container.addView(v) front_field_container.addView(v)
LinkifyCompat.addLinks(key, Linkify.ALL) key?.let { LinkifyCompat.addLinks(it, Linkify.ALL) }
LinkifyCompat.addLinks(value, Linkify.ALL) value?.let { LinkifyCompat.addLinks(it, Linkify.ALL) }
} }
} }
@ -104,8 +105,7 @@ class PassViewFragment : Fragment() {
LinkifyCompat.addLinks(back_fields, Linkify.ALL) LinkifyCompat.addLinks(back_fields, Linkify.ALL)
val passViewHolder = VerbosePassViewHolder(pass_card) val passViewHolder = VerbosePassViewHolder(pass_card)
passViewHolder.apply(pass, passStore, activity) passViewHolder.apply(pass, passStore, activity!!)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
@ -114,7 +114,6 @@ class PassViewFragment : Fragment() {
val rootView = inflater.inflate(R.layout.activity_pass_view_page, container, false) val rootView = inflater.inflate(R.layout.activity_pass_view_page, container, false)
arguments?.takeIf { it.containsKey(PassViewActivityBase.EXTRA_KEY_UUID) }?.apply { arguments?.takeIf { it.containsKey(PassViewActivityBase.EXTRA_KEY_UUID) }?.apply {
val uuid = getString(PassViewActivityBase.EXTRA_KEY_UUID) val uuid = getString(PassViewActivityBase.EXTRA_KEY_UUID)
pass = if (uuid != null) { pass = if (uuid != null) {
passStore.getPassbookForId(uuid) ?: passStore.currentPass!! passStore.getPassbookForId(uuid) ?: passStore.currentPass!!
} else { } else {
@ -125,10 +124,10 @@ class PassViewFragment : Fragment() {
return rootView return rootView
} }
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
val passExtrasView = activity.layoutInflater.inflate(R.layout.pass_view_extra_data, passExtrasContainer, false) val passExtrasView = activity!!.layoutInflater.inflate(R.layout.pass_view_extra_data, passExtrasContainer, false)
passExtrasContainer.addView(passExtrasView) passExtrasContainer.addView(passExtrasView)
} }
} }

View file

@ -17,13 +17,13 @@ class PassViewHelper(private val context: Activity) {
if (bitmap != null) { if (bitmap != null) {
imageView.setImageBitmap(bitmap) imageView.setImageBitmap(bitmap)
imageView.visibility = View.VISIBLE imageView.visibility = View.VISIBLE
imageView.layoutParams = getLayoutParamsSoThatWeHaveMinimumAFingerInHeight(imageView, bitmap) imageView.layoutParams = getLayoutParamsMinHeight(imageView, bitmap)
} else { } else {
imageView.visibility = View.GONE imageView.visibility = View.GONE
} }
} }
fun getLayoutParamsSoThatWeHaveMinimumAFingerInHeight(imageView: ImageView, bitmap: Bitmap) private fun getLayoutParamsMinHeight(imageView: ImageView, bitmap: Bitmap)
= imageView.layoutParams!!.apply { = imageView.layoutParams!!.apply {
height = if (bitmap.height < fingerSize) { height = if (bitmap.height < fingerSize) {
fingerSize fingerSize
@ -33,5 +33,4 @@ class PassViewHelper(private val context: Activity) {
} }
val windowWidth by lazy { context.windowManager.getSizeAsPointCompat().x } val windowWidth by lazy { context.windowManager.getSizeAsPointCompat().x }
} }

View file

@ -2,7 +2,7 @@ package org.ligi.passandroid.ui
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem import android.view.MenuItem
import org.ligi.passandroid.R import org.ligi.passandroid.R

View file

@ -3,10 +3,9 @@ package org.ligi.passandroid.ui
import android.Manifest import android.Manifest
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import android.support.v7.app.AppCompatDelegate.MODE_NIGHT_AUTO import androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_AUTO
import android.support.v7.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import org.ligi.kaxt.recreateWhenPossible
import org.ligi.passandroid.App import org.ligi.passandroid.App
import org.ligi.passandroid.R import org.ligi.passandroid.R
import permissions.dispatcher.NeedsPermission import permissions.dispatcher.NeedsPermission
@ -27,15 +26,14 @@ class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPref
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == getString(R.string.preference_key_nightmode)) { if (key == getString(R.string.preference_key_nightmode)) {
@AppCompatDelegate.NightMode val nightMode = App.settings.getNightMode() @AppCompatDelegate.NightMode val nightMode = App.settings.getNightMode()
if (nightMode == MODE_NIGHT_AUTO) { if (nightMode == MODE_NIGHT_AUTO) {
PrefsFragmentPermissionsDispatcher.ensureDayNightWithCheck(this) ensureDayNightWithPermissionCheck()
} }
AppCompatDelegate.setDefaultNightMode(nightMode) AppCompatDelegate.setDefaultNightMode(nightMode)
activity.recreateWhenPossible() activity?.recreate()
} }
} }
@ -51,7 +49,7 @@ class PrefsFragment : PreferenceFragmentCompat(), SharedPreferences.OnSharedPref
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
PrefsFragmentPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults) onRequestPermissionsResult(requestCode, grantResults)
} }
} }

View file

@ -8,7 +8,7 @@ import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Environment import android.os.Environment
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.support.v4.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.ligi.passandroid.App import org.ligi.passandroid.App
@ -57,7 +57,7 @@ class SearchPassesIntentService : IntentService("SearchPassesIntentService") {
val preferences = PreferenceManager.getDefaultSharedPreferences(applicationContext) val preferences = PreferenceManager.getDefaultSharedPreferences(applicationContext)
for (path in PastLocationsStore(preferences, tracker).locations) { for (path in PastLocationsStore(preferences, tracker).locations) {
search_in(File(path), false) searchIn(File(path), false)
} }
// note to future_me: yea one thinks we only need to search root here, but root was /system for me and so // note to future_me: yea one thinks we only need to search root here, but root was /system for me and so
@ -69,19 +69,19 @@ class SearchPassesIntentService : IntentService("SearchPassesIntentService") {
// up the refreshing of passes as it took so long to traverse all files on the SDCard // up the refreshing of passes as it took so long to traverse all files on the SDCard
// one could think about not going there anymore but a short look at this showed that it seems cost more time to check than what it gains // one could think about not going there anymore but a short look at this showed that it seems cost more time to check than what it gains
// in download there are mostly single files in a flat dir - no huge tree behind this imho // in download there are mostly single files in a flat dir - no huge tree behind this imho
search_in(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), true) searchIn(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), true)
// | /system // | /system
search_in(Environment.getRootDirectory(), true) searchIn(Environment.getRootDirectory(), true)
// | /mnt/sdcard // | /mnt/sdcard
search_in(Environment.getExternalStorageDirectory(), true) searchIn(Environment.getExternalStorageDirectory(), true)
// | /cache // | /cache
search_in(Environment.getDownloadCacheDirectory(), true) searchIn(Environment.getDownloadCacheDirectory(), true)
// | /data // | /data
search_in(Environment.getDataDirectory(), true) searchIn(Environment.getDataDirectory(), true)
notifyManager!!.cancel(PROGRESS_NOTIFICATION_ID) notifyManager!!.cancel(PROGRESS_NOTIFICATION_ID)
bus.post(ScanFinishedEvent(foundList!!)) bus.post(ScanFinishedEvent(foundList!!))
@ -90,7 +90,7 @@ class SearchPassesIntentService : IntentService("SearchPassesIntentService") {
/** /**
* recursive voyage starting at path to find files named .pkpass * recursive voyage starting at path to find files named .pkpass
*/ */
private fun search_in(path: File, recursive: Boolean) { private fun searchIn(path: File, recursive: Boolean) {
if (System.currentTimeMillis() - lastProgressUpdate > 1000) { if (System.currentTimeMillis() - lastProgressUpdate > 1000) {
lastProgressUpdate = System.currentTimeMillis() lastProgressUpdate = System.currentTimeMillis()
@ -114,7 +114,7 @@ class SearchPassesIntentService : IntentService("SearchPassesIntentService") {
} }
Log.i("search " + file.absoluteFile) Log.i("search " + file.absoluteFile)
if (recursive && file.isDirectory) { if (recursive && file.isDirectory) {
search_in(file, true) searchIn(file, true)
} else if (file.name.toLowerCase().endsWith(".pkpass") || file.name.toLowerCase().endsWith(".espass")) { } else if (file.name.toLowerCase().endsWith(".pkpass") || file.name.toLowerCase().endsWith(".espass")) {
Log.i("found" + file.absolutePath) Log.i("found" + file.absolutePath)
@ -149,10 +149,8 @@ class SearchPassesIntentService : IntentService("SearchPassesIntentService") {
} }
companion object { companion object {
const val PROGRESS_NOTIFICATION_ID = 1
val PROGRESS_NOTIFICATION_ID = 1 const val FOUND_NOTIFICATION_ID = 2
val FOUND_NOTIFICATION_ID = 2 const val REQUEST_CODE = 1
val REQUEST_CODE = 1
} }
} }

View file

@ -5,7 +5,7 @@ import android.app.PendingIntent
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.support.v4.app.NotificationCompat import androidx.core.app.NotificationCompat
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.PassBitmapDefinitions import org.ligi.passandroid.model.PassBitmapDefinitions
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui package org.ligi.passandroid.ui
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.view.MenuItem import android.view.MenuItem
import com.github.salomonbrys.kodein.instance import com.github.salomonbrys.kodein.instance
import com.ortiz.touch.TouchImageView import com.ortiz.touch.TouchImageView

View file

@ -39,7 +39,7 @@ object UnzipPassController {
tempFile.delete() tempFile.delete()
} catch (e: Exception) { } catch (e: Exception) {
App.tracker.trackException("problem processing InputStream", e, false) App.tracker.trackException("problem processing InputStream", e, false)
spec.failCallback?.fail("problem with temp file" + e) spec.failCallback?.fail("problem with temp file: $e")
} }
} }
@ -47,12 +47,12 @@ object UnzipPassController {
private fun processFile(spec: FileUnzipControllerSpec) { private fun processFile(spec: FileUnzipControllerSpec) {
var uuid = UUID.randomUUID().toString() var uuid = UUID.randomUUID().toString()
val path = File(spec.context.cacheDir, "temp/" + uuid) val path = File(spec.context.cacheDir, "temp/$uuid")
path.mkdirs() path.mkdirs()
if (!path.exists()) { if (!path.exists()) {
spec.failCallback?.fail("Problem creating the temp dir: " + path) spec.failCallback?.fail("Problem creating the temp dir: $path")
return return
} }
@ -66,36 +66,31 @@ object UnzipPassController {
} }
val manifest_json: JSONObject
val manifestFile = File(path, "manifest.json") val manifestFile = File(path, "manifest.json")
val espassFile = File(path, "main.json") val espassFile = File(path, "main.json")
val manifestJSON: JSONObject
if (manifestFile.exists()) { when {
try { manifestFile.exists() -> try {
val readToString = manifestFile.bufferedReader().readText() val readToString = manifestFile.bufferedReader().readText()
manifest_json = readJSONSafely(readToString)!! manifestJSON = readJSONSafely(readToString)!!
uuid = manifest_json.getString("pass.json") uuid = manifestJSON.getString("pass.json")
} catch (e: Exception) { } catch (e: Exception) {
spec.failCallback?.fail("Problem with manifest.json: " + e) spec.failCallback?.fail("Problem with manifest.json: $e")
return return
} }
espassFile.exists() -> try {
} else if (espassFile.exists()) {
try {
val readToString = espassFile.bufferedReader().readText() val readToString = espassFile.bufferedReader().readText()
manifest_json = readJSONSafely(readToString)!! manifestJSON = readJSONSafely(readToString)!!
uuid = manifest_json.getString("id") uuid = manifestJSON.getString("id")
} catch (e: Exception) { } catch (e: Exception) {
spec.failCallback?.fail("Problem with manifest.json: " + e) spec.failCallback?.fail("Problem with manifest.json: $e")
return return
} }
else -> {
} else {
val bitmap = BitmapFactory.decodeFile(spec.zipFileString) val bitmap = BitmapFactory.decodeFile(spec.zipFileString)
val resources = spec.context.resources val resources = spec.context.resources
if (bitmap != null) { if (bitmap != null) {
val imagePass = createPassForImageImport(resources) val imagePass = createPassForImageImport(resources)
val pathForID = spec.passStore.getPathForID(imagePass.id) val pathForID = spec.passStore.getPathForID(imagePass.id)
@ -138,22 +133,22 @@ object UnzipPassController {
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
} }
spec.failCallback?.fail("Pass is not espass or pkpass format :-(") spec.failCallback?.fail("Pass is not espass or pkpass format :-(")
return return
} }
spec.targetPath.mkdirs()
val rename_file = File(spec.targetPath, uuid)
if (spec.overwrite && rename_file.exists()) {
rename_file.deleteRecursively()
} }
if (!rename_file.exists()) { spec.targetPath.mkdirs()
path.renameTo(rename_file) val renamedFile = File(spec.targetPath, uuid)
if (spec.overwrite && renamedFile.exists()) {
renamedFile.deleteRecursively()
}
if (!renamedFile.exists()) {
path.renameTo(renamedFile)
} else { } else {
Log.i("Pass with same ID exists") Log.i("Pass with same ID exists")
} }

View file

@ -2,7 +2,7 @@ package org.ligi.passandroid.ui
import android.app.Activity import android.app.Activity
import android.app.ProgressDialog import android.app.ProgressDialog
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import org.ligi.passandroid.R import org.ligi.passandroid.R
import org.ligi.passandroid.model.InputStreamWithSource import org.ligi.passandroid.model.InputStreamWithSource
import org.ligi.passandroid.model.PassStore import org.ligi.passandroid.model.PassStore

View file

@ -1,6 +1,6 @@
package org.ligi.passandroid.ui; package org.ligi.passandroid.ui;
import android.support.annotation.IntDef; import androidx.annotation.IntDef;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import static android.view.View.GONE; import static android.view.View.GONE;

View file

@ -8,8 +8,8 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import androidx.fragment.app.Fragment;
import android.support.v7.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import android.util.Log; import android.util.Log;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -90,6 +90,7 @@ import java.util.Map;
* @author Brad Drehmer * @author Brad Drehmer
* @author gcstang * @author gcstang
*/ */
@SuppressWarnings("WeakerAccess")
public class BarCodeIntentIntegrator { public class BarCodeIntentIntegrator {
public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits public static final int REQUEST_CODE = 0x0000c0de; // Only use bottom 16 bits
@ -130,7 +131,7 @@ public class BarCodeIntentIntegrator {
private String buttonYes; private String buttonYes;
private String buttonNo; private String buttonNo;
private List<String> targetApplications; private List<String> targetApplications;
private final Map<String, Object> moreExtras = new HashMap<String, Object>(3); private final Map<String, Object> moreExtras = new HashMap<>(3);
/** /**
* @param activity {@link Activity} invoking the integration * @param activity {@link Activity} invoking the integration
@ -313,7 +314,7 @@ public class BarCodeIntentIntegrator {
* @see android.app.Activity#startActivityForResult(Intent, int) * @see android.app.Activity#startActivityForResult(Intent, int)
* @see android.app.Fragment#startActivityForResult(Intent, int) * @see android.app.Fragment#startActivityForResult(Intent, int)
*/ */
protected void startActivityForResult(Intent intent, int code) { private void startActivityForResult(Intent intent, @SuppressWarnings("SameParameterValue") int code) {
if (fragment == null) { if (fragment == null) {
activity.startActivityForResult(intent, code); activity.startActivityForResult(intent, code);
} else { } else {

View file

@ -1,8 +1,8 @@
package org.ligi.passandroid.ui.edit package org.ligi.passandroid.ui.edit
import android.content.Intent import android.content.Intent
import android.support.v4.app.Fragment import androidx.fragment.app.Fragment
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import android.view.View import android.view.View
import android.widget.RadioButton import android.widget.RadioButton
import kotlinx.android.synthetic.main.barcode_edit.view.* import kotlinx.android.synthetic.main.barcode_edit.view.*
@ -14,14 +14,11 @@ import org.ligi.passandroid.ui.BarcodeUIController
import org.ligi.passandroid.ui.PassViewHelper import org.ligi.passandroid.ui.PassViewHelper
import java.util.* import java.util.*
class BarcodeEditController(val rootView: View, internal val context: AppCompatActivity, barCode: BarCode) { class BarcodeEditController(private val rootView: View, internal val context: AppCompatActivity, barCode: BarCode) {
private var barcodeFormat: PassBarCodeFormat?
var barcodeFormat: PassBarCodeFormat? private val intentFragment: Fragment
internal val intentFragment: Fragment
class IntentFragment : Fragment() { class IntentFragment : Fragment() {
var scanCallback: (String) -> Unit = {} var scanCallback: (String) -> Unit = {}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
@ -37,7 +34,7 @@ class BarcodeEditController(val rootView: View, internal val context: AppCompatA
rootView.barcodeRadioGroup.addView(radioButton) rootView.barcodeRadioGroup.addView(radioButton)
radioButton.text = it.name radioButton.text = it.name
radioButton.setOnCheckedChangeListener { buttonView, isChecked -> radioButton.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) { if (isChecked) {
barcodeFormat = it barcodeFormat = it
refresh() refresh()
@ -53,7 +50,7 @@ class BarcodeEditController(val rootView: View, internal val context: AppCompatA
intentFragment = IntentFragment() intentFragment = IntentFragment()
barcodeFormat = barCode.format barcodeFormat = barCode.format
rootView.randomButton.setOnClickListener({ rootView.randomButton.setOnClickListener {
rootView.messageInput.setText(when (barcodeFormat) { rootView.messageInput.setText(when (barcodeFormat) {
EAN_8 -> getRandomEAN8() EAN_8 -> getRandomEAN8()
EAN_13 -> getRandomEAN13() EAN_13 -> getRandomEAN13()
@ -61,9 +58,9 @@ class BarcodeEditController(val rootView: View, internal val context: AppCompatA
else -> UUID.randomUUID().toString().toUpperCase() else -> UUID.randomUUID().toString().toUpperCase()
}) })
refresh() refresh()
}) }
rootView.scanButton.setOnClickListener({ rootView.scanButton.setOnClickListener {
val barCodeIntentIntegrator = BarCodeIntentIntegrator(intentFragment) val barCodeIntentIntegrator = BarCodeIntentIntegrator(intentFragment)
if (barcodeFormat == QR_CODE) { if (barcodeFormat == QR_CODE) {
@ -72,7 +69,7 @@ class BarcodeEditController(val rootView: View, internal val context: AppCompatA
barCodeIntentIntegrator.initiateScan(setOf(barcodeFormat!!.name)) barCodeIntentIntegrator.initiateScan(setOf(barcodeFormat!!.name))
} }
}) }
intentFragment.scanCallback = { newMessage -> intentFragment.scanCallback = { newMessage ->
rootView.messageInput.setText(newMessage) rootView.messageInput.setText(newMessage)

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui.edit package org.ligi.passandroid.ui.edit
import android.os.Bundle import android.os.Bundle
import android.support.v4.app.Fragment import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -26,7 +26,7 @@ class FieldsEditFragment : Fragment() {
this.inflater = inflater this.inflater = inflater
val inflate = inflater.inflate(R.layout.edit_fields, container, false) val inflate = inflater.inflate(R.layout.edit_fields, container, false)
isEditingHiddenFields = arguments.getBoolean(ARGUMENT_KEY) arguments?.let { isEditingHiddenFields = it.getBoolean(ARGUMENT_KEY) }
if (isEditingHiddenFields) { if (isEditingHiddenFields) {
inflate.add_field.setText(R.string.add_back_fields) inflate.add_field.setText(R.string.add_back_fields)
@ -74,7 +74,7 @@ class FieldsEditFragment : Fragment() {
companion object { companion object {
private val ARGUMENT_KEY = "KEY" private const val ARGUMENT_KEY = "KEY"
fun create(primary: Boolean): FieldsEditFragment { fun create(primary: Boolean): FieldsEditFragment {
val fieldsEditFragment = FieldsEditFragment() val fieldsEditFragment = FieldsEditFragment()

View file

@ -46,12 +46,12 @@ class ImageEditHelper(private val context: Activity, private val passStore: Pass
companion object { companion object {
private val REQ_CODE_OFFSET = 5555 private const val REQ_CODE_OFFSET = 5555
val REQ_CODE_PICK_LOGO = 1 + REQ_CODE_OFFSET const val REQ_CODE_PICK_LOGO = 1 + REQ_CODE_OFFSET
val REQ_CODE_PICK_ICON = 2 + REQ_CODE_OFFSET const val REQ_CODE_PICK_ICON = 2 + REQ_CODE_OFFSET
val REQ_CODE_PICK_STRIP = 3 + REQ_CODE_OFFSET const val REQ_CODE_PICK_STRIP = 3 + REQ_CODE_OFFSET
val REQ_CODE_PICK_THUMBNAIL = 4 + REQ_CODE_OFFSET const val REQ_CODE_PICK_THUMBNAIL = 4 + REQ_CODE_OFFSET
val REQ_CODE_PICK_FOOTER = 5 + REQ_CODE_OFFSET const val REQ_CODE_PICK_FOOTER = 5 + REQ_CODE_OFFSET
@Pass.PassBitmap @Pass.PassBitmap
fun getImageStringByRequestCode(requestCode: Int): String? = when (requestCode) { fun getImageStringByRequestCode(requestCode: Int): String? = when (requestCode) {

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui.edit.dialogs package org.ligi.passandroid.ui.edit.dialogs
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.support.v7.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus
import org.ligi.kaxt.inflate import org.ligi.kaxt.inflate
import org.ligi.passandroid.R import org.ligi.passandroid.R

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui.edit.dialogs package org.ligi.passandroid.ui.edit.dialogs
import android.content.Context import android.content.Context
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui.edit.dialogs package org.ligi.passandroid.ui.edit.dialogs
import android.content.Context import android.content.Context
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater import android.view.LayoutInflater
import kotlinx.android.synthetic.main.edit_color.view.* import kotlinx.android.synthetic.main.edit_color.view.*
import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.EventBus

View file

@ -1,7 +1,7 @@
package org.ligi.passandroid.ui.pass_view_holder package org.ligi.passandroid.ui.pass_view_holder
import android.app.Activity import android.app.Activity
import android.support.v7.widget.CardView import androidx.cardview.widget.CardView
import android.view.View import android.view.View
import kotlinx.android.synthetic.main.pass_list_item.view.* import kotlinx.android.synthetic.main.pass_list_item.view.*
import kotlinx.android.synthetic.main.time_and_nav.view.* import kotlinx.android.synthetic.main.time_and_nav.view.*

View file

@ -3,8 +3,8 @@ package org.ligi.passandroid.ui.pass_view_holder
import android.app.Activity import android.app.Activity
import android.app.DatePickerDialog import android.app.DatePickerDialog
import android.app.TimePickerDialog import android.app.TimePickerDialog
import android.support.v7.app.AlertDialog import androidx.appcompat.app.AlertDialog
import android.support.v7.widget.CardView import androidx.cardview.widget.CardView
import android.view.View.VISIBLE import android.view.View.VISIBLE
import android.widget.DatePicker import android.widget.DatePicker
import android.widget.TimePicker import android.widget.TimePicker
@ -19,9 +19,9 @@ import org.threeten.bp.ZonedDateTime
class EditViewHolder(view: CardView) : VerbosePassViewHolder(view), TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener { class EditViewHolder(view: CardView) : VerbosePassViewHolder(view), TimePickerDialog.OnTimeSetListener, DatePickerDialog.OnDateSetListener {
lateinit private var time: ZonedDateTime private lateinit var time: ZonedDateTime
lateinit private var pass: PassImpl private lateinit var pass: PassImpl
lateinit private var passStore: PassStore private lateinit var passStore: PassStore
override fun apply(pass: Pass, passStore: PassStore, activity: Activity) { override fun apply(pass: Pass, passStore: PassStore, activity: Activity) {
super.apply(pass, passStore, activity) super.apply(pass, passStore, activity)
@ -30,7 +30,7 @@ class EditViewHolder(view: CardView) : VerbosePassViewHolder(view), TimePickerDi
this.passStore = passStore this.passStore = passStore
val calendarTimespan = pass.calendarTimespan val calendarTimespan = pass.calendarTimespan
time = if (calendarTimespan != null && calendarTimespan.from != null) { time = if (calendarTimespan?.from != null) {
calendarTimespan.from calendarTimespan.from
} else { } else {
ZonedDateTime.now() ZonedDateTime.now()

View file

@ -1,8 +1,8 @@
package org.ligi.passandroid.ui.pass_view_holder package org.ligi.passandroid.ui.pass_view_holder
import android.app.Activity import android.app.Activity
import android.support.v7.widget.CardView import androidx.cardview.widget.CardView
import android.support.v7.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import android.text.format.DateUtils import android.text.format.DateUtils
import android.view.View.* import android.view.View.*
import kotlinx.android.synthetic.main.pass_list_item.view.* import kotlinx.android.synthetic.main.pass_list_item.view.*

Some files were not shown because too many files have changed in this diff Show more