Merge pull request #2351 from open-keychain/sql-delight
Use SqlDelight in favor of ContentProviders
This commit is contained in:
commit
63b37deafa
|
@ -1,6 +1,7 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'witness'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'com.squareup.sqldelight'
|
||||
// apply plugin: 'com.github.kt3k.coveralls'
|
||||
|
||||
dependencies {
|
||||
|
@ -8,12 +9,12 @@ dependencies {
|
|||
// NOTE: libraries are pinned to a specific build, see below
|
||||
|
||||
// from local Android SDK
|
||||
compile 'com.android.support:support-v4:27.0.2'
|
||||
compile 'com.android.support:appcompat-v7:27.0.2'
|
||||
compile 'com.android.support:design:27.0.2'
|
||||
compile 'com.android.support:recyclerview-v7:27.0.2'
|
||||
compile 'com.android.support:cardview-v7:27.0.2'
|
||||
compile 'com.android.support:support-annotations:27.0.2'
|
||||
compile 'com.android.support:support-v4:27.1.1'
|
||||
compile 'com.android.support:appcompat-v7:27.1.1'
|
||||
compile 'com.android.support:design:27.1.1'
|
||||
compile 'com.android.support:recyclerview-v7:27.1.1'
|
||||
compile 'com.android.support:cardview-v7:27.1.1'
|
||||
compile 'com.android.support:support-annotations:27.1.1'
|
||||
|
||||
// JCenter etc.
|
||||
compile 'com.journeyapps:zxing-android-embedded:3.4.0'
|
||||
|
@ -27,15 +28,15 @@ dependencies {
|
|||
|
||||
// UI
|
||||
compile 'org.sufficientlysecure:html-textview:3.1'
|
||||
compile 'com.splitwise:tokenautocomplete:2.0.8@aar'
|
||||
compile 'com.jpardogo.materialtabstrip:library:1.1.1'
|
||||
compile 'com.getbase:floatingactionbutton:1.10.1'
|
||||
compile 'com.nispok:snackbar:2.11.0'
|
||||
compile 'com.cocosw:bottomsheet:1.3.1@aar'
|
||||
|
||||
// RecyclerView
|
||||
compile 'com.tonicartos:superslim:0.4.13'
|
||||
compile 'com.futuremind.recyclerfastscroll:fastscroll:0.2.4'
|
||||
compile 'eu.davidea:flexible-adapter:5.0.5'
|
||||
compile 'eu.davidea:flexible-adapter-ui:1.0.0-b5'
|
||||
compile 'eu.davidea:flexible-adapter-livedata:1.0.0-b2'
|
||||
|
||||
// Material Drawer
|
||||
compile 'com.mikepenz:materialdrawer:5.6.0@aar'
|
||||
|
@ -59,6 +60,9 @@ dependencies {
|
|||
implementation project(':extern:minidns')
|
||||
implementation project(':KeybaseLib')
|
||||
implementation project(':safeslinger-exchange')
|
||||
implementation project(':extern:MaterialChipsInput')
|
||||
|
||||
implementation "android.arch.work:work-runtime:1.0.0-alpha02"
|
||||
|
||||
// Unit tests in the local JVM with Robolectric
|
||||
// https://developer.android.com/training/testing/unit-testing/local-unit-tests.html
|
||||
|
@ -73,9 +77,9 @@ dependencies {
|
|||
// UI testing with Espresso
|
||||
// Force usage of support libs in the test app, since they are internally used by the runner module.
|
||||
// https://github.com/googlesamples/android-testing/blob/master/ui/espresso/BasicSample/app/build.gradle#L28
|
||||
androidTestCompile 'com.android.support:support-annotations:27.0.2'
|
||||
androidTestCompile 'com.android.support:appcompat-v7:27.0.2'
|
||||
androidTestCompile 'com.android.support:design:27.0.2'
|
||||
androidTestCompile 'com.android.support:support-annotations:27.1.1'
|
||||
androidTestCompile 'com.android.support:appcompat-v7:27.1.1'
|
||||
androidTestCompile 'com.android.support:design:27.1.1'
|
||||
androidTestCompile 'com.android.support.test:runner:0.5'
|
||||
androidTestCompile 'com.android.support.test:rules:0.5'
|
||||
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
|
||||
|
@ -96,62 +100,69 @@ dependencies {
|
|||
|
||||
compile "android.arch.lifecycle:extensions:1.0.0"
|
||||
annotationProcessor "android.arch.lifecycle:compiler:1.0.0"
|
||||
|
||||
compile "android.arch.persistence:db-framework:1.0.0"
|
||||
|
||||
// for debugging the db. don't enable by default, this will expose the database no the network!
|
||||
// debugImplementation 'com.amitshekhar.android:debug-db:1.0.3'
|
||||
}
|
||||
|
||||
// Output of ./gradlew -q calculateChecksums
|
||||
// Comment out the libs referenced as git submodules!
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'com.android.support:design:fa5c27a705310e95a8f4099c98777132ed901a0d69178942306bb34cd76f0d57',
|
||||
'eu.davidea:flexible-adapter-ui:7ed5327d15c823e5fcf7d6e1017d8a47d079d1adc7141858f3cb427517ef35cd',
|
||||
'com.android.support:design:7225973f7ee03765008a9c2f17a40b154c6885169fef022276e811c926a2202c',
|
||||
'com.journeyapps:zxing-android-embedded:2422d83c2c09a7b645f516c8458ececba6a7da47b94e40778d876facf495c660',
|
||||
'org.sufficientlysecure:donations:2be4183afa5e35263e37346344cfea48681f3c987e6832dd4acde227c13ccad6',
|
||||
'com.android.support:support-v4:1b2b37169fcccfef5e563d273749e3792decdce9818bc17932403a2363f537b4',
|
||||
'com.futuremind.recyclerfastscroll:fastscroll:ae655201885a9dbb5fabecb4adfefbb23ffdbca26a2b4ea255ec1bf6f214c606',
|
||||
'com.android.support:support-v4:4f41dfc3e89f2738e45c86264a85c0934d055ee8ebe2020e23c97f303b80a48b',
|
||||
'com.mikepenz:fastadapter:21d4ecb5c128bcda37b14e7998d799ed52cfc768b72cdf3d5578bb6775769ebd',
|
||||
'com.mikepenz:materialize:942ccf5e2aa1a46803aa884e8dc7bbaf2a9e8e9996a0cf92e3fe2f44a8592ba4',
|
||||
'com.android.support:appcompat-v7:b2825e8b47f665d3362d8481c8d147d1af9230d16f23a2b94f6ccbc53c68cec1',
|
||||
'com.android.support:appcompat-v7:0c7808fbbc5838d831e32e3c0a6f84e1f2c981deb8f11e010650f2b57923a335',
|
||||
'com.nispok:snackbar:46b5eb9d630d329e13c2ce00ee9fb115ffb66c23c72cff32ee97eedd76824c6f',
|
||||
'com.tonicartos:superslim:ca89b5c674660cc6918a8f8fd385065bffeee27983e0d33c7c2f0ad7b34d2d49',
|
||||
'com.android.support:recyclerview-v7:3eb953930f10941f2b0447ec123a9b03d2746a42a99c523e82c3ece3308ca70b',
|
||||
'com.android.support:cardview-v7:57f867a3c8f33e2d4dc0a03e2dfa03cad6267a908179f04a725a68ea9f0b8ccf',
|
||||
'eu.davidea:flexible-adapter:560e940e8cf0f4ed8f632f5f89527deeda7a61cce5f02f42cc0983f7c0d2de5f',
|
||||
'com.android.support:recyclerview-v7:d735e4727878e99ef3980c10d15dc3468462fd509d4fb60cb8bd20b0f735085c',
|
||||
'com.android.support:cardview-v7:8ed955dd037d82a7b4bbcaedb4f896523c3e4c1bf3ca698ce807c350767a2886',
|
||||
'org.sufficientlysecure:html-textview:ed740adf05cae2373999c7a3047c803183d9807b2cf66162902090d7c112a832',
|
||||
'com.getbase:floatingactionbutton:3edefa511aac4d90794c7b0496aca59cff2eee1e32679247b4f85acbeee05240',
|
||||
'com.android.support:transition:1a7db0453c1467fc8fd815e6d50ca6bb475a7a9ba6b5f3b307329688a7c62a68',
|
||||
'com.android.support:support-media-compat:6dd9327ee9aa467cab479aad97df375072b2b6ba61eadffdaa5a88de3843c457',
|
||||
'com.android.support:support-fragment:e4358388022a2205777575a7251fe357334658e4123d5d6e3b082f5899d9b011',
|
||||
'com.android.support:support-core-utils:b69c6e1e7731b876b910fc7100bcadf40a57f27b32ca26b91400995542112c96',
|
||||
'android.arch.persistence:db-framework:e8310c66979f8823cfe583951abfde96824b176289ba77b750a25be00d25981a',
|
||||
'com.android.support:support-media-compat:55e9837dda88b74a8c812c63a78c63fd83c6c039a8c22d318492663a493585eb',
|
||||
'com.jpardogo.materialtabstrip:library:4ee2f1211c302b45fb8c627cc5b240dc6b38b7aaaab1b8bffc81663e1b108013',
|
||||
'com.android.support:animated-vector-drawable:5b117a2c13a898c2a3c84c480d64edcfac2ef720aa9b742c29249fac774ffc48',
|
||||
'com.android.support:support-core-ui:2284072511a95d504c074de80c82cd33724c6d2754117833b98ba3a09994163e',
|
||||
'com.android.support:support-vector-drawable:bf4f4fcbf58b1380616581224e6487c230bfdb3434ec353d4adaa4b1f4865cfa',
|
||||
'com.android.support:support-compat:ed4d25d91a0b13d8b9def1c0de69ed03d7fb89d50fb37eb0e9b63b0cf7a42357',
|
||||
'com.android.support:support-annotations:af05330d997eb92a066534dbe0a3ea24347d26d7001221092113ae02a8f233da',
|
||||
'android.arch.lifecycle:extensions:851f718fd2afda1e7aa93537dae1a5c1fe47710db62dcd7cd24c4b3b14ef0d90',
|
||||
'com.android.support:support-fragment:ec72d6ac36a1a0e6523bbddba33d73ffad070b9b3dd246cc44d8727a41ddb5e6',
|
||||
'com.android.support:animated-vector-drawable:59670473f6e98fda792f7bef25dd7292b0a3106031c7a5e30eb020bf26f077bd',
|
||||
'com.android.support:support-core-ui:a3ae20e6d5dffba69ac97b99846d2738003af8563843d5f3c9dc4c35b4804241',
|
||||
'com.android.support:support-core-utils:61036832c54e8701aae954fc3bf96d1d80bf8d9dd531bff77d72def456ba087a',
|
||||
'com.android.support:support-vector-drawable:1c0f421114cf4627cf208776d6eb4f76340c78b7e96fe6e12b3e6eb950caf1b9',
|
||||
'com.android.support:transition:c0765b2f3c78696567ec5b3f519d22da1e3df11ac994625adf4bb4dc571caacc',
|
||||
'com.android.support:support-compat:880ce01ff5be42b233ff8ec0c61cefb7dc3dc9500fea9e24423214813ac27ea2',
|
||||
'android.arch.persistence:db:7c0a51d5fc890a8fb94a3370ff599243ec3485cca63daba3cc2bb197835dc521',
|
||||
'android.arch.lifecycle:runtime:094fd793924dd6a5136753e599ac8174a8147f4a401386b694ba7d818c223e2e',
|
||||
'android.arch.lifecycle:livedata-core:14e57ff8ffb65a80c7e72d91f2076acccdaf2970f234c6261e03a6127eb5206b',
|
||||
'android.arch.lifecycle:common:614e31cfd33255dc4d5f5d8e62cfa6be2fbbc2a35643a79dc3ed008004c30807',
|
||||
'android.arch.core:runtime:83400f7575bcfb8a2eeec64e05590f037bfaed1e56aa3a4214d20e55878445e3',
|
||||
'android.arch.core:common:d34824b794bc92ff8f647a9bb13a7c73de920de5b47075b5d2c4f0770e9b8bfd',
|
||||
'com.android.support:support-annotations:3365960206c3d2b09e845f555e7f88f8effc8d2f00b369e66c4be384029299cf',
|
||||
'com.google.zxing:core:bba7724e02a997cec38213af77133ee8e24b0d5cf5fa7ecbc16a4fa93f11ee0d',
|
||||
'org.commonjava.googlecode.markdown4j:markdown4j:28eb991f702c6d85d6cafd68c24d1ce841d1f5c995c943f25aedb433c0c13f60',
|
||||
'com.squareup.okhttp3:okhttp-urlconnection:16a410e5c4457ab381759486df6f840fdc7cc426d67433d4da1b7d65ed2b3b33',
|
||||
'com.squareup.okhttp3:okhttp:a0d01017a42bba26e507fc6d448bb36e536f4b6e612f7c42de30bbdac2b7785e',
|
||||
'org.apache.james:apache-mime4j-dom:e18717fe6d36f32e5c5f7cbeea1a9bf04645fdabc84e7e8374d9da10fd52e78d',
|
||||
'org.apache.james:apache-mime4j-core:561987f604911e1870b2b4eabf0b0658d666c66cb1e65fba3e9e4bffe63acab9',
|
||||
'com.splitwise:tokenautocomplete:f921f83ee26b5265f719b312c30452ef8e219557826c5ce5bf02e29647967939',
|
||||
'com.cocosw:bottomsheet:85bd91fd837b02ebd7a888501cb26035c7cd985a6aa87303fca249da8231a2c3',
|
||||
'eu.davidea:flexible-adapter-livedata:c8718b46ff4fbf290ea18f0c5bfe8326badeadf5fd95899a1404c561a24f48a1',
|
||||
'com.mikepenz:materialdrawer:8bba1428dcef5ad7c2decf49c612ad980b38e2f1031cbd66c152a8a104793929',
|
||||
'com.mikepenz:iconics-core:478d7e245098f7c28b5b20a0e6b1e5cb108ef3eaf595af7190bc60f91063aa3d',
|
||||
'com.mikepenz:google-material-typeface:f27c629ba5d2a90ecfbd7f221ff98cd363e1ee6be06b099b82bae490766e14a5',
|
||||
'com.mikepenz:fontawesome-typeface:ee47b7fe97b90412f01f2fcdd78f65a4edb0ab00006f5ef59ed00516baca9309',
|
||||
'com.mikepenz:community-material-typeface:d6035d261c5eba880cd7fe5dcb8cc00b09bfe6d41063b881b759e9897dc7b7c9',
|
||||
'com.fidesmo:nordpol-android:9a992eca347ff7af6e99ff48078954b44b26f26fdc5463139e340234757a24f7',
|
||||
'com.jakewharton.timber:timber:d553d3d3e883ce7d061f1b21b95d6ee0840f3bfbf6d3bd51c5671f0b0f0b0091',
|
||||
'org.glassfish:javax.annotation:339c876b928766329cc0657920366e75beb25f932b80bb3b26df6c0e687a9582',
|
||||
'com.ryanharter.auto.value:auto-value-parcel-adapter:f730534497f7de81f62f1165df65e750522fdaedabd56031ee1c2d9da2544e17',
|
||||
'com.squareup.okio:okio:734269c3ebc5090e3b23566db558f421f0b4027277c79ad5d176b8ec168bb850',
|
||||
'com.fidesmo:nordpol-core:296e71b12884a9cd28cf00ab908973bbf776a90be1f23ac897380d91604e614d',
|
||||
'com.jakewharton.timber:timber:d553d3d3e883ce7d061f1b21b95d6ee0840f3bfbf6d3bd51c5671f0b0f0b0091',
|
||||
'android.arch.lifecycle:runtime:d0b36278878c82b838acc4308595bec61a3b5f6e7f2acc34172d7e071b2cf26d',
|
||||
'android.arch.lifecycle:common:ff0215b54e7cbaaa898f8fd00e265ed6ea198859e10604bc1c5e78477df48b5c',
|
||||
'android.arch.core:common:5192934cd73df32e2c15722ed7fc488dde90baaec9ae030010dd1a80fb4e74e1',
|
||||
'android.arch.lifecycle:runtime:d0b36278878c82b838acc4308595bec61a3b5f6e7f2acc34172d7e071b2cf26d',
|
||||
'android.arch.core:runtime:9e08fc5c4d6e48f58c6865b55ba0e72a88f907009407767274187a873e524734',
|
||||
'android.arch.core:common:5192934cd73df32e2c15722ed7fc488dde90baaec9ae030010dd1a80fb4e74e1',
|
||||
'android.arch.lifecycle:common:ff0215b54e7cbaaa898f8fd00e265ed6ea198859e10604bc1c5e78477df48b5c',
|
||||
'android.arch.lifecycle:viewmodel:6407c93a5ea9850661dca42a0068d6f3deccefd7228ee69bae1c35d70cbc2557',
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ import com.nispok.snackbar.Snackbar;
|
|||
import org.hamcrest.Matcher;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing;
|
||||
import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow;
|
||||
import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
|
@ -53,7 +52,7 @@ import static org.hamcrest.CoreMatchers.endsWith;
|
|||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSnackbarLineColor;
|
||||
|
||||
|
||||
public class TestHelpers {
|
||||
public class AndroidTestHelpers {
|
||||
|
||||
public static void dismissSnackbar() {
|
||||
onView(withClassName(endsWith("Snackbar")))
|
||||
|
@ -152,7 +151,7 @@ public class TestHelpers {
|
|||
|
||||
public static void cleanupForTests(Context context) throws Exception {
|
||||
|
||||
new KeychainDatabase(context).clearDatabase();
|
||||
KeychainDatabase.getInstance(context).clearDatabase();
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(context, "x.sec.asc");
|
||||
|
@ -161,5 +160,4 @@ public class TestHelpers {
|
|||
PassphraseCacheService.clearCachedPassphrases(context);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -27,8 +27,7 @@ import android.view.View;
|
|||
import com.tokenautocomplete.TokenCompleteTextView;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
|
||||
import org.sufficientlysecure.keychain.provider.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
|
||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
|
||||
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||
|
||||
|
|
|
@ -28,13 +28,9 @@ import android.widget.ViewAnimator;
|
|||
|
||||
import com.nispok.snackbar.Snackbar;
|
||||
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
|
||||
import org.sufficientlysecure.keychain.ui.adapter.KeySectionedListAdapter;
|
||||
import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
|
||||
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
|
@ -90,15 +86,14 @@ public abstract class CustomMatchers {
|
|||
}
|
||||
|
||||
public static Matcher<RecyclerView.ViewHolder> withKeyHolderId(final long keyId) {
|
||||
return new BoundedMatcher<RecyclerView.ViewHolder, KeySectionedListAdapter.KeyItemViewHolder>
|
||||
(KeySectionedListAdapter.KeyItemViewHolder.class) {
|
||||
return new BoundedMatcher<RecyclerView.ViewHolder, RecyclerView.ViewHolder>(RecyclerView.ViewHolder.class) {
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("with ViewHolder id: " + keyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesSafely(KeySectionedListAdapter.KeyItemViewHolder item) {
|
||||
protected boolean matchesSafely(View item) {
|
||||
return item.getItemId() == keyId;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -9,7 +9,6 @@ import android.support.test.InstrumentationRegistry;
|
|||
import android.support.test.rule.ServiceTestRule;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
|
@ -23,17 +22,14 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
import static android.support.test.espresso.Espresso.closeSoftKeyboard;
|
||||
import static android.support.test.espresso.Espresso.onData;
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.action.ViewActions.click;
|
||||
import static android.support.test.espresso.action.ViewActions.typeText;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.core.Is.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.cleanupForTests;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.cleanupForTests;
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
|
|
|
@ -32,7 +32,7 @@ import android.widget.AdapterView;
|
|||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.TestHelpers;
|
||||
import org.sufficientlysecure.keychain.AndroidTestHelpers;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
|
@ -61,11 +61,11 @@ import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
|||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.getImageNames;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.pickRandom;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.getImageNames;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.pickRandom;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.actions.CustomActions.tokenEncryptViewAddToken;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withDisplayedChild;
|
||||
|
@ -95,7 +95,7 @@ public class AsymmetricFileOperationTests {
|
|||
public void setUp() throws Exception {
|
||||
Activity activity = mActivity.getActivity();
|
||||
|
||||
TestHelpers.copyFiles();
|
||||
AndroidTestHelpers.copyFiles();
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(activity, "x.sec.asc");
|
||||
|
|
|
@ -43,9 +43,9 @@ import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
|||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.actions.CustomActions.tokenEncryptViewAddToken;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withDisplayedChild;
|
||||
|
|
|
@ -20,37 +20,27 @@ package org.sufficientlysecure.keychain.ui;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.support.test.espresso.ViewAction;
|
||||
import android.support.test.espresso.action.ViewActions;
|
||||
import android.support.test.espresso.contrib.RecyclerViewActions;
|
||||
import android.support.test.espresso.matcher.ViewMatchers;
|
||||
import android.support.test.rule.ActivityTestRule;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.matcher.CustomMatchers;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.KeychainDatabase;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
import static android.support.test.espresso.Espresso.onData;
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.action.ViewActions.click;
|
||||
import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnHolderItem;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.isDescendantOfA;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyHolderId;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId;
|
||||
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
|
@ -73,7 +63,7 @@ public class EditKeyTest {
|
|||
public void test01Edit() throws Exception {
|
||||
Activity activity = mActivity.getActivity();
|
||||
|
||||
new KeychainDatabase(activity).clearDatabase();
|
||||
KeychainDatabase.getInstance(activity).clearDatabase();
|
||||
|
||||
// import key for testing, get a stable initial state
|
||||
importKeysFromResource(activity, "x.sec.asc");
|
||||
|
|
|
@ -27,18 +27,15 @@ import android.content.Context;
|
|||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.support.test.espresso.contrib.RecyclerViewActions;
|
||||
import android.support.test.espresso.intent.Intents;
|
||||
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.TestHelpers;
|
||||
import org.sufficientlysecure.keychain.matcher.CustomMatchers;
|
||||
import org.sufficientlysecure.keychain.AndroidTestHelpers;
|
||||
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
@ -46,7 +43,6 @@ import org.sufficientlysecure.keychain.util.Preferences;
|
|||
import java.io.File;
|
||||
|
||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static android.support.test.espresso.Espresso.onData;
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
|
||||
import static android.support.test.espresso.Espresso.pressBack;
|
||||
|
@ -67,16 +63,15 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
|||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.dismissSnackbar;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.getImageNames;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.pickRandom;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.dismissSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.getImageNames;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.pickRandom;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withDisplayedChild;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyHolderId;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId;
|
||||
import static org.sufficientlysecure.keychain.matcher.DrawableMatcher.withDrawable;
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
|
@ -104,7 +99,7 @@ public class MiscCryptOperationTests {
|
|||
|
||||
mActivity = mActivityRule.getActivity();
|
||||
|
||||
TestHelpers.copyFiles();
|
||||
AndroidTestHelpers.copyFiles();
|
||||
|
||||
// import these two, make sure they're there
|
||||
importKeysFromResource(mActivity, "x.sec.asc");
|
||||
|
|
|
@ -52,8 +52,8 @@ import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
|||
import static android.support.test.espresso.matcher.ViewMatchers.withText;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.checkSnackbar;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.randomString;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.isRecyclerItemView;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withEncryptionStatus;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withSignatureNone;
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.sufficientlysecure.keychain.ui;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Instrumentation.ActivityResult;
|
||||
import android.content.Intent;
|
||||
import android.support.test.espresso.intent.rule.IntentsTestRule;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.FixMethodOrder;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runners.MethodSorters;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.compatibility.ClipboardReflection;
|
||||
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
|
||||
import org.sufficientlysecure.keychain.provider.TemporaryFileProvider;
|
||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.action.ViewActions.click;
|
||||
import static android.support.test.espresso.intent.Intents.intending;
|
||||
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
|
||||
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasExtra;
|
||||
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasType;
|
||||
import static android.support.test.espresso.intent.matcher.UriMatchers.hasHost;
|
||||
import static android.support.test.espresso.intent.matcher.UriMatchers.hasScheme;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.hamcrest.CoreMatchers.startsWith;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.checkAndDismissSnackbar;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.cleanupForTests;
|
||||
|
||||
//TODO This test is disabled because it needs to be fixed to work with updated code
|
||||
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
|
||||
//@RunWith(AndroidJUnit4.class)
|
||||
//@LargeTest
|
||||
public class ViewKeyAdvShareTest {
|
||||
|
||||
@Rule
|
||||
public final IntentsTestRule<ViewKeyAdvActivity> mActivityRule
|
||||
= new IntentsTestRule<ViewKeyAdvActivity>(ViewKeyAdvActivity.class) {
|
||||
@Override
|
||||
protected Intent getActivityIntent() {
|
||||
Intent intent = super.getActivityIntent();
|
||||
intent.setData(KeyRings.buildGenericKeyRingUri(0x9D604D2F310716A3L));
|
||||
intent.putExtra(ViewKeyAdvActivity.EXTRA_SELECTED_TAB, ViewKeyAdvActivity.TAB_SHARE);
|
||||
return intent;
|
||||
}
|
||||
};
|
||||
private Activity mActivity;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mActivity = mActivityRule.getActivity();
|
||||
|
||||
cleanupForTests(mActivity);
|
||||
}
|
||||
|
||||
//@Test
|
||||
public void testShareOperations() throws Exception {
|
||||
|
||||
// no-op should yield snackbar
|
||||
onView(withId(R.id.view_key_action_fingerprint_clipboard)).perform(click());
|
||||
checkAndDismissSnackbar(Style.OK, R.string.fingerprint_copied_to_clipboard);
|
||||
assertThat("clipboard data is fingerprint", ClipboardReflection.getClipboardText(mActivity),
|
||||
is("c619d53f7a5f96f391a84ca79d604d2f310716a3"));
|
||||
|
||||
intending(allOf(
|
||||
hasAction("android.intent.action.CHOOSER"),
|
||||
hasExtra(equalTo(Intent.EXTRA_INTENT), allOf(
|
||||
hasAction(Intent.ACTION_SEND),
|
||||
hasType("text/plain"),
|
||||
hasExtra(is(Intent.EXTRA_TEXT), is("openpgp4fpr:c619d53f7a5f96f391a84ca79d604d2f310716a3")),
|
||||
hasExtra(is(Intent.EXTRA_STREAM),
|
||||
allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY)))
|
||||
))
|
||||
)).respondWith(new ActivityResult(Activity.RESULT_OK, null));
|
||||
onView(withId(R.id.view_key_action_fingerprint_share)).perform(click());
|
||||
|
||||
onView(withId(R.id.view_key_action_key_clipboard)).perform(click());
|
||||
checkAndDismissSnackbar(Style.OK, R.string.key_copied_to_clipboard);
|
||||
assertThat("clipboard data is key",
|
||||
ClipboardReflection.getClipboardText(mActivity), startsWith("----"));
|
||||
|
||||
intending(allOf(
|
||||
hasAction("android.intent.action.CHOOSER"),
|
||||
hasExtra(equalTo(Intent.EXTRA_INTENT), allOf(
|
||||
hasAction(Intent.ACTION_SEND),
|
||||
hasType("text/plain"),
|
||||
hasExtra(is(Intent.EXTRA_TEXT), startsWith("----")),
|
||||
hasExtra(is(Intent.EXTRA_STREAM),
|
||||
allOf(hasScheme("content"), hasHost(TemporaryFileProvider.AUTHORITY)))
|
||||
))
|
||||
)).respondWith(new ActivityResult(Activity.RESULT_OK, null));
|
||||
onView(withId(R.id.view_key_action_key_share)).perform(click());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -40,7 +40,7 @@ import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant;
|
|||
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static org.hamcrest.CoreMatchers.allOf;
|
||||
import static org.sufficientlysecure.keychain.TestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.AndroidTestHelpers.importKeysFromResource;
|
||||
import static org.sufficientlysecure.keychain.actions.CustomActions.tokenEncryptViewAddToken;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyItemId;
|
||||
import static org.sufficientlysecure.keychain.matcher.CustomMatchers.withKeyToken;
|
||||
|
|
36
OpenKeychain/src/debug/res/xml/shortcuts.xml
Normal file
36
OpenKeychain/src/debug/res/xml/shortcuts.xml
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_comment_text_grey600_24dp"
|
||||
android:shortcutId="encrypt_text"
|
||||
android:shortcutLongLabel="@string/btn_encrypt_text"
|
||||
android:shortcutShortLabel="@string/btn_encrypt_text">
|
||||
<intent
|
||||
android:action="org.sufficientlysecure.keychain.action.ENCRYPT_FILES"
|
||||
android:targetClass="org.sufficientlysecure.keychain.ui.EncryptTextActivity"
|
||||
android:targetPackage="org.sufficientlysecure.keychain.debug" />
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_folder_grey_24dp"
|
||||
android:shortcutId="encrypt_files"
|
||||
android:shortcutLongLabel="@string/btn_encrypt_files"
|
||||
android:shortcutShortLabel="@string/btn_encrypt_files">
|
||||
<intent
|
||||
android:action="org.sufficientlysecure.keychain.action.ENCRYPT_TEXT"
|
||||
android:targetClass="org.sufficientlysecure.keychain.ui.EncryptFilesActivity"
|
||||
android:targetPackage="org.sufficientlysecure.keychain.debug" />
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/status_signature_unverified_cutout_24dp"
|
||||
android:shortcutId="debug_actions"
|
||||
android:shortcutLongLabel="@string/shortcut_debug"
|
||||
android:shortcutShortLabel="@string/shortcut_debug">
|
||||
<intent
|
||||
android:action="org.sufficientlysecure.keychain.debug"
|
||||
android:targetClass="org.sufficientlysecure.keychain.ui.DebugActionsActivity"
|
||||
android:targetPackage="org.sufficientlysecure.keychain.debug" />
|
||||
</shortcut>
|
||||
</shortcuts>
|
|
@ -95,15 +95,6 @@
|
|||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Keychain.Light">
|
||||
<!-- broadcast receiver for Wi-Fi Connection -->
|
||||
<receiver
|
||||
android:name=".network.NetworkReceiver"
|
||||
android:enabled="false"
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<!-- broadcast receiver for Orbots status -->
|
||||
<receiver android:name=".network.orbot.OrbotStatusReceiver">
|
||||
<intent-filter>
|
||||
|
@ -128,6 +119,8 @@
|
|||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcuts" />
|
||||
</activity>
|
||||
<!-- singleTop for NFC dispatch, see SecurityTokenOperationActivity -->
|
||||
<activity
|
||||
|
@ -177,15 +170,6 @@
|
|||
<data android:mimeType="vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.key" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.ViewCertActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
android:label="@string/title_view_cert"
|
||||
android:parentActivityName=".ui.keyview.ViewKeyActivity">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".ui.keyview.ViewKeyActivity" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.SafeSlingerActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden|keyboard"
|
||||
|
@ -983,6 +967,12 @@
|
|||
android:name=".remote.ui.RemoteDisplayTransferCodeActivity"
|
||||
android:theme="@style/Theme.Keychain.Transparent"/>
|
||||
|
||||
<activity android:name=".ui.DebugActionsActivity">
|
||||
<intent-filter>
|
||||
<action android:name="org.sufficientlysecure.keychain.debug" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Usb interceptor activity -->
|
||||
<activity
|
||||
android:name=".ui.UsbEventReceiverActivity"
|
||||
|
@ -1070,21 +1060,6 @@
|
|||
android:resource="@xml/sync_adapter_contacts_structure" />
|
||||
</service>
|
||||
|
||||
<!-- keyserver sync service -->
|
||||
<service
|
||||
android:name=".service.KeyserverSyncAdapterService"
|
||||
android:exported="true"
|
||||
android:process=":sync"
|
||||
tools:ignore="ExportedService">
|
||||
<intent-filter>
|
||||
<action android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.content.SyncAdapter"
|
||||
android:resource="@xml/sync_adapter_keys" />
|
||||
</service>
|
||||
|
||||
<!-- Storage Provider for temporary decrypted files.
|
||||
For security considerations, read class! -->
|
||||
<provider
|
||||
|
|
|
@ -1,473 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.support.v4.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Animation.AnimationListener;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Transformation;
|
||||
import android.widget.AbsListView;
|
||||
|
||||
|
||||
/**
|
||||
* Same as SwipeRefreshLayout, only updateContentOffsetTop and REFRESH_TRIGGER_DISTANCE
|
||||
* have been modified!
|
||||
*/
|
||||
public class NoScrollableSwipeRefreshLayout extends ViewGroup {
|
||||
private static final long RETURN_TO_ORIGINAL_POSITION_TIMEOUT = 300;
|
||||
private static final float ACCELERATE_INTERPOLATION_FACTOR = 1.5f;
|
||||
private static final float DECELERATE_INTERPOLATION_FACTOR = 2f;
|
||||
private static final float PROGRESS_BAR_HEIGHT = 4;
|
||||
private static final float MAX_SWIPE_DISTANCE_FACTOR = .6f;
|
||||
private static final int REFRESH_TRIGGER_DISTANCE = 200;
|
||||
|
||||
private SwipeProgressBar mProgressBar; //the thing that shows progress is going
|
||||
private View mTarget; //the content that gets pulled down
|
||||
private int mOriginalOffsetTop;
|
||||
private OnRefreshListener mListener;
|
||||
private MotionEvent mDownEvent;
|
||||
private int mFrom;
|
||||
private boolean mRefreshing = false;
|
||||
private int mTouchSlop;
|
||||
private float mDistanceToTriggerSync = -1;
|
||||
private float mPrevY;
|
||||
private int mMediumAnimationDuration;
|
||||
private float mFromPercentage = 0;
|
||||
private float mCurrPercentage = 0;
|
||||
private int mProgressBarHeight;
|
||||
private int mCurrentTargetOffsetTop;
|
||||
// Target is returning to its start offset because it was cancelled or a
|
||||
// refresh was triggered.
|
||||
private boolean mReturningToStart;
|
||||
private final DecelerateInterpolator mDecelerateInterpolator;
|
||||
private final AccelerateInterpolator mAccelerateInterpolator;
|
||||
private static final int[] LAYOUT_ATTRS = new int[] {
|
||||
android.R.attr.enabled
|
||||
};
|
||||
|
||||
private final Animation mAnimateToStartPosition = new Animation() {
|
||||
@Override
|
||||
public void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
int targetTop = 0;
|
||||
if (mFrom != mOriginalOffsetTop) {
|
||||
targetTop = (mFrom + (int)((mOriginalOffsetTop - mFrom) * interpolatedTime));
|
||||
}
|
||||
int offset = targetTop - mTarget.getTop();
|
||||
final int currentTop = mTarget.getTop();
|
||||
if (offset + currentTop < 0) {
|
||||
offset = 0 - currentTop;
|
||||
}
|
||||
setTargetOffsetTopAndBottom(offset);
|
||||
}
|
||||
};
|
||||
|
||||
private Animation mShrinkTrigger = new Animation() {
|
||||
@Override
|
||||
public void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
float percent = mFromPercentage + ((0 - mFromPercentage) * interpolatedTime);
|
||||
mProgressBar.setTriggerPercentage(percent);
|
||||
}
|
||||
};
|
||||
|
||||
private final AnimationListener mReturnToStartPositionListener = new BaseAnimationListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
// Once the target content has returned to its start position, reset
|
||||
// the target offset to 0
|
||||
mCurrentTargetOffsetTop = 0;
|
||||
}
|
||||
};
|
||||
|
||||
private final AnimationListener mShrinkAnimationListener = new BaseAnimationListener() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
mCurrPercentage = 0;
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mReturnToStartPosition = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mReturningToStart = true;
|
||||
animateOffsetToStartPosition(mCurrentTargetOffsetTop + getPaddingTop(),
|
||||
mReturnToStartPositionListener);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Cancel the refresh gesture and animate everything back to its original state.
|
||||
private final Runnable mCancel = new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mReturningToStart = true;
|
||||
// Timeout fired since the user last moved their finger; animate the
|
||||
// trigger to 0 and put the target back at its original position
|
||||
if (mProgressBar != null) {
|
||||
mFromPercentage = mCurrPercentage;
|
||||
mShrinkTrigger.setDuration(mMediumAnimationDuration);
|
||||
mShrinkTrigger.setAnimationListener(mShrinkAnimationListener);
|
||||
mShrinkTrigger.reset();
|
||||
mShrinkTrigger.setInterpolator(mDecelerateInterpolator);
|
||||
startAnimation(mShrinkTrigger);
|
||||
}
|
||||
animateOffsetToStartPosition(mCurrentTargetOffsetTop + getPaddingTop(),
|
||||
mReturnToStartPositionListener);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Simple constructor to use when creating a SwipeRefreshLayout from code.
|
||||
* @param context
|
||||
*/
|
||||
public NoScrollableSwipeRefreshLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that is called when inflating SwipeRefreshLayout from XML.
|
||||
* @param context
|
||||
* @param attrs
|
||||
*/
|
||||
public NoScrollableSwipeRefreshLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
|
||||
mMediumAnimationDuration = getResources().getInteger(
|
||||
android.R.integer.config_mediumAnimTime);
|
||||
|
||||
setWillNotDraw(false);
|
||||
mProgressBar = new SwipeProgressBar(this);
|
||||
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
mProgressBarHeight = (int) (metrics.density * PROGRESS_BAR_HEIGHT);
|
||||
mDecelerateInterpolator = new DecelerateInterpolator(DECELERATE_INTERPOLATION_FACTOR);
|
||||
mAccelerateInterpolator = new AccelerateInterpolator(ACCELERATE_INTERPOLATION_FACTOR);
|
||||
|
||||
final TypedArray a = context.obtainStyledAttributes(attrs, LAYOUT_ATTRS);
|
||||
setEnabled(a.getBoolean(0, true));
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
removeCallbacks(mCancel);
|
||||
removeCallbacks(mReturnToStartPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
removeCallbacks(mReturnToStartPosition);
|
||||
removeCallbacks(mCancel);
|
||||
}
|
||||
|
||||
private void animateOffsetToStartPosition(int from, AnimationListener listener) {
|
||||
mFrom = from;
|
||||
mAnimateToStartPosition.reset();
|
||||
mAnimateToStartPosition.setDuration(mMediumAnimationDuration);
|
||||
mAnimateToStartPosition.setAnimationListener(listener);
|
||||
mAnimateToStartPosition.setInterpolator(mDecelerateInterpolator);
|
||||
mTarget.startAnimation(mAnimateToStartPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener to be notified when a refresh is triggered via the swipe
|
||||
* gesture.
|
||||
*/
|
||||
public void setOnRefreshListener(OnRefreshListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
private void setTriggerPercentage(float percent) {
|
||||
if (percent == 0f) {
|
||||
// No-op. A null trigger means it's uninitialized, and setting it to zero-percent
|
||||
// means we're trying to reset state, so there's nothing to reset in this case.
|
||||
mCurrPercentage = 0;
|
||||
return;
|
||||
}
|
||||
mCurrPercentage = percent;
|
||||
mProgressBar.setTriggerPercentage(percent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the widget that refresh state has changed. Do not call this when
|
||||
* refresh is triggered by a swipe gesture.
|
||||
*
|
||||
* @param refreshing Whether or not the view should show refresh progress.
|
||||
*/
|
||||
public void setRefreshing(boolean refreshing) {
|
||||
if (mRefreshing != refreshing) {
|
||||
ensureTarget();
|
||||
mCurrPercentage = 0;
|
||||
mRefreshing = refreshing;
|
||||
if (mRefreshing) {
|
||||
mProgressBar.start();
|
||||
} else {
|
||||
mProgressBar.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the four colors used in the progress animation. The first color will
|
||||
* also be the color of the bar that grows in response to a user swipe
|
||||
* gesture.
|
||||
*
|
||||
* @param colorRes1 Color resource.
|
||||
* @param colorRes2 Color resource.
|
||||
* @param colorRes3 Color resource.
|
||||
* @param colorRes4 Color resource.
|
||||
*/
|
||||
public void setColorScheme(int colorRes1, int colorRes2, int colorRes3, int colorRes4) {
|
||||
ensureTarget();
|
||||
final Resources res = getResources();
|
||||
final int color1 = res.getColor(colorRes1);
|
||||
final int color2 = res.getColor(colorRes2);
|
||||
final int color3 = res.getColor(colorRes3);
|
||||
final int color4 = res.getColor(colorRes4);
|
||||
mProgressBar.setColorScheme(color1, color2, color3,color4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the SwipeRefreshWidget is actively showing refresh
|
||||
* progress.
|
||||
*/
|
||||
public boolean isRefreshing() {
|
||||
return mRefreshing;
|
||||
}
|
||||
|
||||
private void ensureTarget() {
|
||||
// Don't bother getting the parent height if the parent hasn't been laid out yet.
|
||||
if (mTarget == null) {
|
||||
if (getChildCount() > 1 && !isInEditMode()) {
|
||||
throw new IllegalStateException(
|
||||
"SwipeRefreshLayout can host only one direct child");
|
||||
}
|
||||
mTarget = getChildAt(0);
|
||||
mOriginalOffsetTop = mTarget.getTop() + getPaddingTop();
|
||||
}
|
||||
if (mDistanceToTriggerSync == -1) {
|
||||
if (getParent() != null && ((View)getParent()).getHeight() > 0) {
|
||||
final DisplayMetrics metrics = getResources().getDisplayMetrics();
|
||||
mDistanceToTriggerSync = (int) Math.min(
|
||||
((View) getParent()) .getHeight() * MAX_SWIPE_DISTANCE_FACTOR,
|
||||
REFRESH_TRIGGER_DISTANCE * metrics.density);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
mProgressBar.draw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
final int width = getMeasuredWidth();
|
||||
final int height = getMeasuredHeight();
|
||||
mProgressBar.setBounds(0, 0, width, mProgressBarHeight);
|
||||
if (getChildCount() == 0) {
|
||||
return;
|
||||
}
|
||||
final View child = getChildAt(0);
|
||||
final int childLeft = getPaddingLeft();
|
||||
final int childTop = mCurrentTargetOffsetTop + getPaddingTop();
|
||||
final int childWidth = width - getPaddingLeft() - getPaddingRight();
|
||||
final int childHeight = height - getPaddingTop() - getPaddingBottom();
|
||||
child.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (getChildCount() > 1 && !isInEditMode()) {
|
||||
throw new IllegalStateException("SwipeRefreshLayout can host only one direct child");
|
||||
}
|
||||
if (getChildCount() > 0) {
|
||||
getChildAt(0).measure(
|
||||
MeasureSpec.makeMeasureSpec(
|
||||
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
|
||||
MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(
|
||||
getMeasuredHeight() - getPaddingTop() - getPaddingBottom(),
|
||||
MeasureSpec.EXACTLY));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether it is possible for the child view of this layout to
|
||||
* scroll up. Override this if the child view is a custom view.
|
||||
*/
|
||||
public boolean canChildScrollUp() {
|
||||
if (android.os.Build.VERSION.SDK_INT < 14) {
|
||||
if (mTarget instanceof AbsListView) {
|
||||
final AbsListView absListView = (AbsListView) mTarget;
|
||||
return absListView.getChildCount() > 0
|
||||
&& (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0)
|
||||
.getTop() < absListView.getPaddingTop());
|
||||
} else {
|
||||
return mTarget.getScrollY() > 0;
|
||||
}
|
||||
} else {
|
||||
return ViewCompat.canScrollVertically(mTarget, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
ensureTarget();
|
||||
boolean handled = false;
|
||||
if (mReturningToStart && ev.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mReturningToStart = false;
|
||||
}
|
||||
if (isEnabled() && !mReturningToStart && !canChildScrollUp()) {
|
||||
handled = onTouchEvent(ev);
|
||||
}
|
||||
return !handled ? super.onInterceptTouchEvent(ev) : handled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDisallowInterceptTouchEvent(boolean b) {
|
||||
// Nope.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
boolean handled = false;
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mCurrPercentage = 0;
|
||||
mDownEvent = MotionEvent.obtain(event);
|
||||
mPrevY = mDownEvent.getY();
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mDownEvent != null && !mReturningToStart) {
|
||||
final float eventY = event.getY();
|
||||
float yDiff = eventY - mDownEvent.getY();
|
||||
if (yDiff > mTouchSlop) {
|
||||
// User velocity passed min velocity; trigger a refresh
|
||||
if (yDiff > mDistanceToTriggerSync) {
|
||||
// User movement passed distance; trigger a refresh
|
||||
startRefresh();
|
||||
handled = true;
|
||||
break;
|
||||
} else {
|
||||
// Just track the user's movement
|
||||
setTriggerPercentage(
|
||||
mAccelerateInterpolator.getInterpolation(
|
||||
yDiff / mDistanceToTriggerSync));
|
||||
float offsetTop = yDiff;
|
||||
if (mPrevY > eventY) {
|
||||
offsetTop = yDiff - mTouchSlop;
|
||||
}
|
||||
updateContentOffsetTop((int) (offsetTop));
|
||||
if (mPrevY > eventY && (mTarget.getTop() < mTouchSlop)) {
|
||||
// If the user puts the view back at the top, we
|
||||
// don't need to. This shouldn't be considered
|
||||
// cancelling the gesture as the user can restart from the top.
|
||||
removeCallbacks(mCancel);
|
||||
} else {
|
||||
updatePositionTimeout();
|
||||
}
|
||||
mPrevY = event.getY();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (mDownEvent != null) {
|
||||
mDownEvent.recycle();
|
||||
mDownEvent = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
|
||||
private void startRefresh() {
|
||||
removeCallbacks(mCancel);
|
||||
mReturnToStartPosition.run();
|
||||
setRefreshing(true);
|
||||
mListener.onRefresh();
|
||||
}
|
||||
|
||||
private void updateContentOffsetTop(int targetTop) {
|
||||
final int currentTop = mTarget.getTop();
|
||||
if (targetTop > mDistanceToTriggerSync) {
|
||||
targetTop = (int) mDistanceToTriggerSync;
|
||||
} else if (targetTop < 0) {
|
||||
targetTop = 0;
|
||||
}
|
||||
// setTargetOffsetTopAndBottom(targetTop - currentTop);
|
||||
}
|
||||
|
||||
private void setTargetOffsetTopAndBottom(int offset) {
|
||||
mTarget.offsetTopAndBottom(offset);
|
||||
mCurrentTargetOffsetTop = mTarget.getTop();
|
||||
}
|
||||
|
||||
private void updatePositionTimeout() {
|
||||
removeCallbacks(mCancel);
|
||||
postDelayed(mCancel, RETURN_TO_ORIGINAL_POSITION_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Classes that wish to be notified when the swipe gesture correctly
|
||||
* triggers a refresh should implement this interface.
|
||||
*/
|
||||
public interface OnRefreshListener {
|
||||
void onRefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple AnimationListener to avoid having to implement unneeded methods in
|
||||
* AnimationListeners.
|
||||
*/
|
||||
private class BaseAnimationListener implements AnimationListener {
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,6 +37,8 @@ public final class Constants {
|
|||
public static final boolean DEBUG_SYNC_REMOVE_CONTACTS = false;
|
||||
public static final boolean DEBUG_KEYSERVER_SYNC = false;
|
||||
|
||||
public static final boolean IS_RUNNING_UNITTEST = isRunningUnitTest();
|
||||
|
||||
public static final String TAG = DEBUG ? "Keychain D" : "Keychain";
|
||||
|
||||
public static final String PACKAGE_NAME = "org.sufficientlysecure.keychain";
|
||||
|
@ -108,9 +110,14 @@ public final class Constants {
|
|||
public static final File APP_DIR = new File(Environment.getExternalStorageDirectory(), "OpenKeychain");
|
||||
}
|
||||
|
||||
public static final class Notification {
|
||||
public static final class NotificationIds {
|
||||
public static final int PASSPHRASE_CACHE = 1;
|
||||
public static final int KEYSERVER_SYNC_FAIL_ORBOT = 2;
|
||||
public static final int KEYSERVER_SYNC = 3;
|
||||
}
|
||||
|
||||
public static final class NotificationChannels {
|
||||
public static final String KEYSERVER_SYNC = "keyserverSync";
|
||||
}
|
||||
|
||||
public static final class Pref {
|
||||
|
@ -145,6 +152,7 @@ public final class Constants {
|
|||
public static final String SYNC_CONTACTS = "syncContacts";
|
||||
public static final String SYNC_KEYSERVER = "syncKeyserver";
|
||||
public static final String ENABLE_WIFI_SYNC_ONLY = "enableWifiSyncOnly";
|
||||
public static final String SYNC_IS_SCHEDULED = "syncIsScheduled";
|
||||
// other settings
|
||||
public static final String EXPERIMENTAL_ENABLE_LINKED_IDENTITIES = "experimentalEnableLinkedIdentities";
|
||||
public static final String EXPERIMENTAL_ENABLE_KEYBASE = "experimentalEnableKeybase";
|
||||
|
@ -205,4 +213,12 @@ public final class Constants {
|
|||
public static final KeyFormat SECURITY_TOKEN_V2_DEC = new RSAKeyFormat(2048, ELEN, RSAKeyFormat.RSAAlgorithmFormat.CRT_WITH_MODULUS);
|
||||
public static final KeyFormat SECURITY_TOKEN_V2_AUTH = new RSAKeyFormat(2048, ELEN, RSAKeyFormat.RSAAlgorithmFormat.CRT_WITH_MODULUS);
|
||||
|
||||
private static boolean isRunningUnitTest() {
|
||||
try {
|
||||
Class.forName("org.sufficientlysecure.keychain.KeychainTestRunner");
|
||||
return true;
|
||||
} catch (ClassNotFoundException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,13 +24,8 @@ import java.util.HashMap;
|
|||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.app.Application;
|
||||
import android.app.job.JobScheduler;
|
||||
|