Merge pull request #2351 from open-keychain/sql-delight

Use SqlDelight in favor of ContentProviders
This commit is contained in:
Vincent Breitmoser 2018-07-04 22:58:56 +02:00 committed by GitHub
commit 63b37deafa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
333 changed files with 11216 additions and 17018 deletions

View file

@ -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',
]
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;
}
};

View file

@ -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)

View file

@ -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");

View file

@ -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;

View file

@ -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");

View file

@ -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");

View file

@ -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;

View file

@ -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());
}
}

View file

@ -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;

View 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>

View file

@ -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

View file

@ -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) {
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;