Merge pull request #743 from nextcloud/androidx

Update to androidx
This commit is contained in:
David Luhmer 2019-04-06 14:13:12 -03:00 committed by GitHub
commit 7d0a35c506
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
71 changed files with 992 additions and 612 deletions

View file

@ -3,6 +3,13 @@
- Single Sign on for all Nextcloud Android Apps!
0.9.9.26
---------------------
- Fix - <a href="https://github.com/owncloud/News-Android-App/issues/726">#726 Add new feed fails</a>
- Fix - <a href="https://github.com/owncloud/News-Android-App/issues/744">#744 Fix issues when adding feeds (Thanks @Unpublished)</a>
- Feature - <a href="https://github.com/owncloud/News-Android-App/issues/747">#747 Add option to share article when using chrome-custom-tabs</a>
0.9.9.25
---------------------
- Fix - app crashes

View file

@ -16,24 +16,31 @@ android {
minSdkVersion Integer.parseInt(project.ANDROID_BUILD_MIN_SDK_VERSION)
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
//testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunner "de.luhmer.owncloudnewsreader.CustomTestRunner"
vectorDrawables.useSupportLibrary = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
debug {
shrinkResources true
minifyEnabled true
// TODO check if proguard-android.txt is used at all.. it's supposed to get it from the sdk. so we can delete it in this repo!
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
testProguardFiles 'proguard-test.pro'
pseudoLocalesEnabled true
}
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
testProguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
testProguardFiles 'proguard-test.pro'
//signingConfig signingConfigs.debug
}
}
@ -63,10 +70,11 @@ android {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
// if set to true (default), stops the build if errors are found.
abortOnError true
abortOnError false
// if true, only report errors.
ignoreWarnings true
}
sourceSets {
@ -82,19 +90,22 @@ android {
exclude 'LICENSE.txt'
exclude 'META-INF/services/javax.annotation.processing.Processor'
}
// Gradle automatically adds 'android.test.runner' as a dependency.
useLibrary 'android.test.runner'
useLibrary 'android.test.base'
useLibrary 'android.test.mock'
}
repositories {
mavenCentral()
jcenter()
maven { url "https://jitpack.io" }
maven { url 'https://guardian.github.com/maven/repo-releases' } //needed for com.gu:option:1.3 in Android-DirectoryChooser
maven { url "https://dl.bintray.com/lukaville/maven" } //Needed for com.nbsp:library:1.02 in Material File Picker
maven { url "https://jitpack.io" }
}
final SUPPORT_VERSION = '28.0.0'
dependencies {
// core android studio module
//compile project(':core')
@ -103,22 +114,26 @@ dependencies {
// implementation 'com.google.android.gms:play-services:4.2.42'
//implementation project(':Android-SingleSignOn')
//implementation project(path: ':MaterialShowcaseView:library', configuration: 'default')
implementation 'com.github.nextcloud:Android-SingleSignOn:0.3.0'
//implementation 'com.github.nextcloud:Android-SingleSignOn:e781a33e01'
implementation 'com.github.nextcloud:Android-SingleSignOn:unit-testing-SNAPSHOT'
implementation 'com.github.David-Development:MaterialShowcaseView:bf6afa225d'
implementation "com.android.support:support-v4:${SUPPORT_VERSION}"
implementation "com.android.support:support-compat:${SUPPORT_VERSION}"
implementation "com.android.support:appcompat-v7:${SUPPORT_VERSION}"
implementation "com.android.support:design:${SUPPORT_VERSION}"
implementation "com.android.support:palette-v7:${SUPPORT_VERSION}"
implementation "com.android.support:recyclerview-v7:${SUPPORT_VERSION}"
implementation "com.android.support:customtabs:${SUPPORT_VERSION}"
implementation "com.android.support:cardview-v7:${SUPPORT_VERSION}"
// https://mvnrepository.com/artifact/androidx.legacy/legacy-support-v4
implementation "androidx.legacy:legacy-support-v4:1.0.0"
implementation "androidx.core:core:1.1.0-alpha05"
implementation "androidx.appcompat:appcompat:1.1.0-alpha02"
// https://mvnrepository.com/artifact/com.google.android.material/material
implementation "com.google.android.material:material:1.1.0-alpha04"
implementation "androidx.palette:palette:1.0.0"
implementation "androidx.recyclerview:recyclerview:1.1.0-alpha3"
implementation "androidx.browser:browser:1.0.0"
implementation "androidx.cardview:cardview:1.0.0"
//implementation 'de.mrmaffen:holocircularprogressbar:1.0.1'
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'com.jakewharton:butterknife:10.1.0'
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
compileOnly 'com.google.auto.value:auto-value:1.1'
annotationProcessor 'com.google.auto.value:auto-value:1.1'
@ -127,12 +142,14 @@ dependencies {
implementation 'org.greenrobot:eventbus:3.1.1'
implementation 'de.greenrobot:greendao:2.0.0'
implementation 'de.greenrobot:greendao-generator:2.0.0'
implementation ('de.greenrobot:greendao-generator:2.0.0') {
exclude group: 'org.freemarker'
}
//implementation 'org.freemarker:freemarker:2.3.23' //Required for DAO generation
//implementation 'org.apache.commons:commons-lang3:3.4'
implementation 'com.github.gabrielemariotti.changeloglib:changelog:2.1.0'
implementation 'org.jsoup:jsoup:1.11.3'
implementation ('net.rdrei.android.dirchooser:library:3.0@aar') { transitive = true; }
implementation ('net.rdrei.android.dirchooser:library:3.0@aar') { transitive = true }
implementation 'com.google.dagger:dagger:2.16'
@ -154,38 +171,67 @@ dependencies {
extraImplementation 'com.github.tommus:youtube-android-player-api:1.2.2'
testImplementation 'org.robolectric:robolectric:3.0-rc3'
testImplementation 'junit:junit:4.12'
testImplementation("org.mockito:mockito-core:1.10.19") {
exclude group: 'org.hamcrest'
}
testImplementation 'com.google.dexmaker:dexmaker:1.2'
testImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
testImplementation 'com.squareup.okhttp3:mockwebserver:3.8.0'
testImplementation 'com.squareup.okhttp3:mockwebserver:3.14.0'
androidTestAnnotationProcessor "com.google.dagger:dagger-compiler:2.16"
//androidTestCompile 'com.squareup.okhttp:mockwebserver:2.5.0'
// https://mvnrepository.com/artifact/com.squareup.okhttp3/mockwebserver
androidTestImplementation group: 'com.squareup.okhttp3', name: 'mockwebserver', version: '3.8.0'
//androidTestImplementation group: 'com.squareup.okhttp3', name: 'mockwebserver', version: '3.14.0'
androidTestAnnotationProcessor 'com.google.auto.value:auto-value:1.5.2'
androidTestImplementation "com.android.support:support-annotations:${SUPPORT_VERSION}"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
androidTestImplementation('com.android.support.test.espresso:espresso-contrib:2.2') {
// this library uses the newest app compat v22 but the espresso contrib still v21.
// you have to specifically exclude the older versions of the contrib library or
// there will be some conflicts
exclude group: 'com.android.support', module: 'appcompat'
exclude group: 'com.android.support', module: 'support-v4'
exclude module: 'recyclerview-v7'
}
androidTestImplementation 'tools.fastlane:screengrab:1.2.0'
androidTestImplementation("org.mockito:mockito-core:1.10.19") {
exclude group: 'org.hamcrest'
}
androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
//androidTestImplementation 'org.mockito:mockito-core:2.25.1'
androidTestImplementation 'org.mockito:mockito-android:2.18.3'
//androidTestImplementation 'com.google.dexmaker:dexmaker:1.2'
//androidTestImplementation 'com.google.dexmaker:dexmaker-mockito:1.2'
//androidTestImplementation 'org.robolectric:robolectric:3.0-rc3'
// Core library
androidTestImplementation 'androidx.test:core:1.1.0'
// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test:rules:1.1.1'
// Assertions
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.ext:truth:1.1.0'
androidTestImplementation 'com.google.truth:truth:0.42'
// Espresso dependencies
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-web:3.1.1'
androidTestImplementation 'androidx.test.espresso.idling:idling-concurrent:3.1.1'
// The following Espresso dependency can be either "implementation"
// or "androidTestImplementation", depending on whether you want the
// dependency to appear on your APK's compile classpath or the test APK
// classpath.
//androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.1.1'
}
/*
// Workaround for https://github.com/mockito/mockito/issues/1511#issuecomment-458544398
configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'net.bytebuddy') {
details.useVersion "1.8.22"
}
}
}
*/

View file

@ -1,61 +0,0 @@
# This is a configuration file for ProGuard.
# http://proguard.sourceforge.net/index.html#manual/usage.html
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-verbose
# Optimization is turned off by default. Dex does not like code run
# through the ProGuard optimize and preverify steps (and performs some
# of these optimizations on its own).
-dontoptimize
-dontpreverify
# Note that if you want to enable optimization, you cannot just
# include optimization flags in your own project configuration file;
# instead you will need to point to the
# "proguard-android-optimize.txt" file instead of this one from your
# project.properties file.
-keepattributes *Annotation*
-keep public class com.google.vending.licensing.ILicensingService
-keep public class com.android.vending.licensing.ILicensingService
# For native methods, see http://proguard.sourceforge.net/manual/examples.html#native
-keepclasseswithmembernames class * {
native <methods>;
}
# keep setters in Views so that animations can still work.
# see http://proguard.sourceforge.net/manual/examples.html#beans
-keepclassmembers public class * extends android.view.View {
void set*(***);
*** get*();
}
# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
# For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
-keepclassmembers class **.R$* {
public static <fields>;
}
# The support library contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
# platform version. We know about them, and they are safe.
-dontwarn android.support.**

View file

@ -29,8 +29,6 @@
-dontwarn org.mockito.**
-keepnames class * implements java.io.Serializable
-keepclassmembers class * implements java.io.Serializable {
@ -113,4 +111,58 @@
-keep class de.greenrobot.** { *; }
-dontwarn de.greenrobot.daogenerator.DaoGenerator
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao { *; }
-keepclassmembers class * extends de.greenrobot.dao.AbstractDao { *; }
###############
# Guava (official)
## Not yet defined: follow https://github.com/google/guava/issues/2117
# Guava (unofficial)
## https://github.com/google/guava/issues/2926#issuecomment-325455128
## https://stackoverflow.com/questions/9120338/proguard-configuration-for-guava-with-obfuscation-and-optimization
-dontwarn com.google.common.base.**
-dontwarn com.google.errorprone.annotations.**
-dontwarn com.google.j2objc.annotations.**
-dontwarn java.lang.ClassValue
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn javax.annotation.**
-dontwarn javax.inject.**
-dontwarn sun.misc.Unsafe
# Added for guava 23.5-android
-dontwarn afu.org.checkerframework.**
-dontwarn org.checkerframework.**
#-ignorewarnings
#-keep class * {
# public private *;
#}
### OkHttp
# https://github.com/square/okhttp/blob/master/README.md
-dontwarn okhttp3.**
-dontwarn okio.**
-dontwarn javax.annotation.**
-dontwarn org.conscrypt.**
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**
# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform
-keep interface org.conscrypt.Conscrypt { *; }
-keep class org.conscrypt.Conscrypt { *; }
# https://stackoverflow.com/a/39777485
# Also, note that this rule should be added to the regular proguard file(the one of listed in proguardFiles) and not the test one(declared as testProguardFile)
# java.lang.NoSuchMethodError: No virtual method getParameter
-keepclasseswithmembers public class com.nextcloud.android.sso.aidl.NextcloudRequest { *; }

View file

@ -0,0 +1,48 @@
# proguard-test.pro:
-include proguard-rules.pro
-keepattributes SourceFile,LineNumberTable
-dontwarn androidx.test.espresso.**
###############
# Required for Mockito
-keep class retrofit2.NextcloudRetrofitApiBuilder { *; }
-keep class net.bytebuddy.* { *; }
-dontwarn net.bytebuddy.**
-keep class module-info
-keepattributes Module*
-dontwarn org.mockito.**
# Proguard rules that are applied to your test apk/code.
-ignorewarnings
-keepattributes *Annotation*
-dontnote junit.framework.**
-dontnote junit.runner.**
-dontwarn android.test.**
-dontwarn android.support.test.**
-dontwarn org.junit.**
-dontwarn org.hamcrest.**
-dontwarn com.squareup.javawriter.JavaWriter
-dontwarn androidx.concurrent.futures.AbstractResolvableFuture
-dontwarn org.conscrypt.Conscrypt
#com.google.common.util.concurrent.ListenableFuture
-keep interface okhttp3.internal.platform.ConscryptPlatform
-keep class okhttp3.internal.platform.ConscryptPlatform
-keep class org.conscrypt.Conscrypt { *; }
-keep interface org.conscrypt.Conscrypt { *; }
#org.conscrypt
-dontwarn org.conscrypt.**
#-keep class org.conscrypt.** { *; }
#-keep interface org.conscrypt.** { *; }

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
package="your.package.name">
<uses-sdk tools:overrideLibrary="android.support.test.uiautomator.v18"/>
<application>
<!-- You don't need to include android:required="false" if your app's minSdkVersion is 28 or higher. -->
<uses-library android:name="android.test.runner" android:required="false" />
<uses-library android:name="android.test.base" android:required="false" />
<uses-library android:name="android.test.mock" android:required="false" />
</application>
</manifest>

View file

@ -0,0 +1,133 @@
package com.nextcloud.android.sso.api;
import com.nextcloud.android.sso.aidl.NextcloudRequest;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.runners.MockitoJUnitRunner;
import javax.inject.Inject;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import de.luhmer.owncloudnewsreader.NewFeedActivity;
import de.luhmer.owncloudnewsreader.R;
import de.luhmer.owncloudnewsreader.TestApplication;
import de.luhmer.owncloudnewsreader.di.ApiProvider;
import de.luhmer.owncloudnewsreader.di.TestApiProvider;
import de.luhmer.owncloudnewsreader.di.TestComponent;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.typeText;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.hasErrorText;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
//@RunWith(AndroidJUnit4.class)
@RunWith(MockitoJUnitRunner.class)
@LargeTest
public class NewFeedTests {
@Rule
public ActivityTestRule<NewFeedActivity> activityRule = new ActivityTestRule<>(NewFeedActivity.class);
protected @Inject ApiProvider mApi;
@Before
public void setUp() {
TestComponent ac = (TestComponent) ((TestApplication)(activityRule.getActivity().getApplication())).getAppComponent();
ac.inject(this);
// Reset Spy object
mApi.initApi(null);
//reset(((TestApiProvider)mApi).networkRequestSpy);
}
@Test
public void addNewFeed() {
String feed = TestApiProvider.NEW_FEED_SUCCESS;
// Type text and then press the button.
onView(withId(R.id.et_feed_url)).perform(typeText(feed), closeSoftKeyboard());
onView(withId(R.id.btn_addFeed)).perform(click());
try {
verifyRequest(feed);
//onView(withId(R.id.et_feed_url)).check(matches(hasErrorText(nullValue(String.class))));
// Check Activity existed
Thread.sleep(1000);
assertFalse(activityRule.getActivity().getWindow().getDecorView().isShown());
} catch (Exception e) {
fail(e.getMessage());
}
}
@Test
public void addExistingFeed() {
String feed = TestApiProvider.NEW_FEED_EXISTING;
// Type text and then press the button.
onView(withId(R.id.et_feed_url)).perform(typeText(feed), closeSoftKeyboard());
onView(withId(R.id.btn_addFeed)).perform(click());
try {
verifyRequest(feed);
// Check Activity still open
Thread.sleep(1000);
assertTrue(activityRule.getActivity().getWindow().getDecorView().isShown());
onView(withId(R.id.et_feed_url)).check(matches(hasErrorText(is("Feed konnte nicht hinzugefügt werden: Existiert bereits"))));
} catch (Exception e) {
fail(e.getMessage());
}
}
@Test
public void addInvalidFeed() {
String feed = TestApiProvider.NEW_FEED_FAIL;
// Type text and then press the button.
onView(withId(R.id.et_feed_url)).perform(typeText(feed), closeSoftKeyboard());
onView(withId(R.id.btn_addFeed)).perform(click());
try {
verifyRequest(feed);
// Check Activity still open
Thread.sleep(1000);
assertTrue(activityRule.getActivity().getWindow().getDecorView().isShown());
onView(withId(R.id.et_feed_url)).check(matches(hasErrorText(is("FeedIo\\Adapter\\NotFoundException: Client error: `GET http://feeds2.feedburner.com/stadt-bremerhaven/dqXM222` resulted in a `404 Feed not found error: ..."))));
} catch (Exception e) {
fail(e.getMessage());
}
}
// Verify that the API was actually called
private void verifyRequest(String feed) throws Exception {
NetworkRequest nr = ((TestApiProvider)mApi).networkRequestSpy;
ArgumentCaptor<NextcloudRequest> argument = ArgumentCaptor.forClass(NextcloudRequest.class);
verify(nr, timeout(2000)).performNetworkRequest(argument.capture(), any());
assertEquals("/index.php/apps/news/api/v1-2/feeds", argument.getValue().getUrl());
assertEquals(feed, argument.getValue().getParameter().get("url"));
assertEquals("0", argument.getValue().getParameter().get("folderId"));
}
}

View file

@ -0,0 +1,27 @@
package de.luhmer.owncloudnewsreader;
import android.app.Application;
import android.content.Context;
import androidx.test.runner.AndroidJUnitRunner;
public class CustomTestRunner extends AndroidJUnitRunner {
/*
@Override
public void onCreate(Bundle arguments) {
// The workaround for Mockito issue #922
// https://github.com/mockito/mockito/issues/922
arguments.putString("notPackage", "net.bytebuddy");
super.onCreate(arguments);
}
*/
public Application newApplication(ClassLoader cl, String className, Context context) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
return super.newApplication(cl, TestApplication.class.getName(), context);
}
}

View file

@ -0,0 +1,21 @@
package de.luhmer.owncloudnewsreader;
import de.luhmer.owncloudnewsreader.di.DaggerTestComponent;
import de.luhmer.owncloudnewsreader.di.TestApiModule;
public class TestApplication extends NewsReaderApplication {
@Override
public void initDaggerAppComponent() {
// Dagger%COMPONENT_NAME%
mAppComponent = DaggerTestComponent.builder()
.apiModule(new TestApiModule(this))
.build();
// If a Dagger 2 component does not have any constructor arguments for any of its modules,
// then we can use .create() as a shortcut instead:
//mAppComponent = DaggerAppComponent.create();
}
}

View file

@ -0,0 +1,76 @@
package de.luhmer.owncloudnewsreader.di;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.helper.SingleAccountHelper;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
import java.io.IOException;
import de.luhmer.owncloudnewsreader.SettingsActivity;
import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class TestApiModule extends ApiModule {
private Application application;
public TestApiModule(Application application) {
super(application);
this.application = application;
}
@Override
public SharedPreferences providesSharedPreferences() {
SharedPreferences sharedPrefs = mock(SharedPreferences.class);
final Context context = mock(Context.class);
when(context.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPrefs);
// Turn on Single-Sign-On
when(sharedPrefs.getBoolean(SettingsActivity.SW_USE_SINGLE_SIGN_ON, false)).thenReturn(true);
// Set cache size
when(sharedPrefs.getString(eq(SettingsActivity.SP_MAX_CACHE_SIZE), any())).thenReturn("500");
// Add dummy account
String accountName = "test-account";
String username = "david";
String token = "abc";
String server_url = "http://nextcloud.com/";
String prefKey = "PREF_ACCOUNT_STRING" + accountName;
SingleSignOnAccount ssoAccount = new SingleSignOnAccount(accountName, username, token, server_url);
try {
AccountImporter.getSharedPreferences(application).edit().putString(prefKey, SingleSignOnAccount.toString(ssoAccount)).commit();
} catch (IOException e) {
e.printStackTrace();
}
//try {
// when(sharedPrefs.getString(eq(prefKey), any())).thenReturn(SingleSignOnAccount.toString(ssoAccount));
//} catch (IOException e) {
// e.printStackTrace();
//}
SingleAccountHelper.setCurrentAccount(application, accountName);
return sharedPrefs;
}
@Override
protected ApiProvider provideAPI(MemorizingTrustManager mtm, SharedPreferences sp) {
ApiProvider apiProvider = new TestApiProvider(mtm, sp, application);
return apiProvider;
}
}

View file

@ -0,0 +1,111 @@
package de.luhmer.owncloudnewsreader.di;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Looper;
import android.os.NetworkOnMainThreadException;
import android.util.Log;
import com.nextcloud.android.sso.aidl.NextcloudRequest;
import com.nextcloud.android.sso.api.NetworkRequest;
import com.nextcloud.android.sso.api.NextcloudAPI;
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
import org.mockito.Mockito;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import de.luhmer.owncloudnewsreader.helper.GsonConfig;
import de.luhmer.owncloudnewsreader.reader.nextcloud.API;
import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager;
import retrofit2.NextcloudRetrofitApiBuilder;
import static org.mockito.ArgumentMatchers.any;
public class TestApiProvider extends ApiProvider {
private static final String TAG = TestApiProvider.class.getCanonicalName();
public static final String NEW_FEED_SUCCESS = "http://test.de/new";
public static final String NEW_FEED_EXISTING = "http://test.de/existing";
public static final String NEW_FEED_FAIL = "http://test.de/fail";
private static final String NEW_FEED_EXISTING_ERROR_MESSAGE = "{\"message\":\"Feed konnte nicht hinzugef\\u00fcgt werden: Existiert bereits\"}";
private static final String NEW_FEED_FAIL_ERROR_MESSAGE = "{\"message\":\"FeedIo\\\\Adapter\\\\NotFoundException: Client error: `GET http:\\/\\/feeds2.feedburner.com\\/stadt-bremerhaven\\/dqXM222` resulted in a `404 Feed not found error: FeedBurner cannot locate this feed URI.` response:\\n\\u003Chtml\\u003E\\n\\u003Chead\\u003E\\n\\u003Cstyle type=\\\"text\\/css\\\"\\u003E\\na:link, a:visited {\\n color: #000099;\\n text-decoration: underline;\\n}\\n\\na:hover {\\n (truncated...)\\n in \\/apps2\\/news\\/lib\\/Fetcher\\/Client\\/FeedIoClient.php:57\\nStack trace:\\n#0 \\/apps2\\/news\\/vendor\\/debril\\/feed-io\\/src\\/FeedIo\\/Reader.php(116): OCA\\\\News\\\\Fetcher\\\\Client\\\\FeedIoClient-\\u003EgetResponse('http:\\/\\/feeds2.f...', Object(DateTime))\\n#1 \\/apps2\\/news\\/vendor\\/debril\\/feed-io\\/src\\/FeedIo\\/FeedIo.php(286): FeedIo\\\\Reader-\\u003Eread('http:\\/\\/feeds2.f...', Object(FeedIo\\\\Feed), Object(DateTime))\\n#2 \\/apps2\\/news\\/lib\\/Fetcher\\/FeedFetcher.php(77): FeedIo\\\\FeedIo-\\u003Eread('http:\\/\\/feeds2.f...')\\n#3 \\/apps2\\/news\\/lib\\/Fetcher\\/Fetcher.php(68): OCA\\\\News\\\\Fetcher\\\\FeedFetcher-\\u003Efetch('http:\\/\\/feeds2.f...', true, NULL, NULL, NULL)\\n#4 \\/apps2\\/news\\/lib\\/Service\\/FeedService.php(116): OCA\\\\News\\\\Fetcher\\\\Fetcher-\\u003Efetch('http:\\/\\/feeds2.f...', true, NULL, NULL, NULL)\\n#5 \\/apps2\\/news\\/lib\\/Controller\\/FeedApiController.php(96): OCA\\\\News\\\\Service\\\\FeedService-\\u003Ecreate('http:\\/\\/feeds2.f...', 0, 'david')\\n#6 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Http\\/Dispatcher.php(166): OCA\\\\News\\\\Controller\\\\FeedApiController-\\u003Ecreate('http:\\/\\/feeds2.f...', 0)\\n#7 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Http\\/Dispatcher.php(99): OC\\\\AppFramework\\\\Http\\\\Dispatcher-\\u003EexecuteController(Object(OCA\\\\News\\\\Controller\\\\FeedApiController), 'create')\\n#8 \\/nextcloud\\/lib\\/private\\/AppFramework\\/App.php(118): OC\\\\AppFramework\\\\Http\\\\Dispatcher-\\u003Edispatch(Object(OCA\\\\News\\\\Controller\\\\FeedApiController), 'create')\\n#9 \\/nextcloud\\/lib\\/private\\/AppFramework\\/Routing\\/RouteActionHandler.php(47): OC\\\\AppFramework\\\\App::main('OCA\\\\\\\\News\\\\\\\\Contro...', 'create', Object(OC\\\\AppFramework\\\\DependencyInjection\\\\DIContainer), Array)\\n#10 [internal function]: OC\\\\AppFramework\\\\Routing\\\\RouteActionHandler-\\u003E__invoke(Array)\\n#11 \\/nextcloud\\/lib\\/private\\/Route\\/Router.php(297): call_user_func(Object(OC\\\\AppFramework\\\\Routing\\\\RouteActionHandler), Array)\\n#12 \\/nextcloud\\/lib\\/base.php(987): OC\\\\Route\\\\Router-\\u003Ematch('\\/apps\\/news\\/api\\/...')\\n#13 \\/nextcloud\\/index.php(42): OC::handleRequest()\\n#14 {main}\"}";
public NewsTestNetworkRequest networkRequestSpy;
TestApiProvider(MemorizingTrustManager mtm, SharedPreferences sp, Context context) {
super(mtm, sp, context);
}
@Override
protected void initSsoApi(final NextcloudAPI.ApiConnectedListener callback) {
NewsTestNetworkRequest networkRequest = new NewsTestNetworkRequest(callback);
networkRequestSpy = Mockito.spy(networkRequest);
// By spying on the method "performNetworkRequest" we can later check if requests were build correctly
try {
Mockito.doCallRealMethod().when(networkRequestSpy).performNetworkRequest(any(), any());
} catch (Exception e) {
e.printStackTrace();
}
NextcloudAPI nextcloudAPI = new NextcloudAPI(GsonConfig.GetGson(), networkRequestSpy);
mApi = new NextcloudRetrofitApiBuilder(nextcloudAPI, API.mApiEndpoint).create(API.class);
}
class NewsTestNetworkRequest extends NetworkRequest {
NewsTestNetworkRequest(NextcloudAPI.ApiConnectedListener callback) {
super(null, null, callback);
}
@Override
protected void connect() {
super.connect();
mCallback.onConnected();
}
@Override
public InputStream performNetworkRequest(NextcloudRequest request, InputStream requestBodyInputStream) throws Exception {
if(Looper.myLooper() == Looper.getMainLooper()) {
throw new NetworkOnMainThreadException();
}
Log.w(TAG, "Requested URL: " + request.getUrl());
InputStream inputStream;
switch (request.getUrl()) {
case "/index.php/apps/news/api/v1-2/feeds":
inputStream = handleCreateFeed(request);
break;
default:
throw new UnsupportedOperationException("Not implemented yet!");
}
return inputStream;
}
// https://github.com/nextcloud/news/blob/master/docs/externalapi/Legacy.md#create-a-feed
private InputStream handleCreateFeed(NextcloudRequest request) throws NextcloudHttpRequestFailedException {
switch (request.getParameter().get("url")) {
case NEW_FEED_SUCCESS:
return stringToInputStream("");
case NEW_FEED_EXISTING:
throw new NextcloudHttpRequestFailedException(409, new Throwable(NEW_FEED_EXISTING_ERROR_MESSAGE));
case NEW_FEED_FAIL:
throw new NextcloudHttpRequestFailedException(422, new Throwable(NEW_FEED_FAIL_ERROR_MESSAGE));
default:
throw new UnsupportedOperationException("Not implemented yet!");
}
}
private InputStream stringToInputStream(String data) {
return new ByteArrayInputStream(data.getBytes(Charset.forName("UTF-8")));
}
}
}

View file

@ -0,0 +1,13 @@
package de.luhmer.owncloudnewsreader.di;
import com.nextcloud.android.sso.api.NewFeedTests;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = { ApiModule.class })
public interface TestComponent extends AppComponent {
void inject(NewFeedTests test);
}

View file

@ -1,8 +1,8 @@
package de.luhmer.owncloudnewsreader.tests;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.runner.RunWith;

View file

@ -4,14 +4,14 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.SystemClock;
import android.preference.PreferenceManager;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.espresso.matcher.ViewMatchers;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import androidx.test.espresso.Espresso;
import androidx.test.espresso.contrib.RecyclerViewActions;
import androidx.test.espresso.matcher.ViewMatchers;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.junit.Before;
import org.junit.Rule;
@ -27,17 +27,19 @@ import de.luhmer.owncloudnewsreader.NewsReaderListActivity;
import de.luhmer.owncloudnewsreader.R;
import de.luhmer.owncloudnewsreader.adapter.NewsListRecyclerAdapter;
import de.luhmer.owncloudnewsreader.adapter.ViewHolder;
import helper.OrientationChangeAction;
import helper.RecyclerViewAssertions;
import static android.support.test.InstrumentationRegistry.getInstrumentation;
import static android.support.test.InstrumentationRegistry.registerInstance;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.InstrumentationRegistry.registerInstance;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.doesNotExist;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.fail;
@ -154,9 +156,9 @@ public class NewsReaderListActivityUiTests {
sleep(0.5f);
if(!testFirstPosition) {
onView(withId(android.support.design.R.id.snackbar_text)).check(matches(isDisplayed()));
onView(withId(com.google.android.material.R.id.snackbar_text)).check(matches(isDisplayed()));
} else {
onView(withId(android.support.design.R.id.snackbar_text)).check(doesNotExist());
onView(withId(com.google.android.material.R.id.snackbar_text)).check(doesNotExist());
}
} catch (NoSuchMethodException e) {
e.printStackTrace();

View file

@ -6,41 +6,50 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.Preference;
import android.preference.PreferenceManager;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import de.luhmer.owncloudnewsreader.NewsReaderListActivity;
import de.luhmer.owncloudnewsreader.R;
import de.luhmer.owncloudnewsreader.helper.ThemeChooser;
import static android.preference.PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES;
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.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.PreferenceMatchers.withKey;
import static android.support.test.espresso.matcher.PreferenceMatchers.withSummary;
import static android.support.test.espresso.matcher.PreferenceMatchers.withTitle;
import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
import static androidx.test.espresso.action.ViewActions.click;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.PreferenceMatchers.withKey;
import static androidx.test.espresso.matcher.PreferenceMatchers.withSummary;
import static androidx.test.espresso.matcher.PreferenceMatchers.withTitle;
import static androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.luhmer.owncloudnewsreader.SettingsActivity.CB_OLED_MODE;
import static de.luhmer.owncloudnewsreader.SettingsActivity.SP_APP_THEME;
import static helper.CustomMatchers.withBackgroundColor;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.core.AllOf.allOf;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
@RunWith(AndroidJUnit4.class)
@LargeTest
@ -58,14 +67,43 @@ public class NightModeTest {
return mActivityRule.getActivity();
}
@Before
public void resetSharedPrefs() {
Context context = getInstrumentation().getTargetContext();
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
// Reset SharedPrefs
// https://developer.android.com/guide/topics/ui/settings#Defaults
mPrefs.edit()
.remove(CB_OLED_MODE)
.remove(SP_APP_THEME)
.commit();
assertThat(mPrefs.contains(SP_APP_THEME), equalTo(false));
assertThat(mPrefs.contains(CB_OLED_MODE), equalTo(false));
SharedPreferences defaultValueSp = context.getSharedPreferences(KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, false).commit();
/*
// Set Fixed time
Instant.now(
Clock.fixed(
Instant.parse( "2019-04-05T18:00:00Z"), ZoneOffset.UTC
)
);
*/
}
@Test
public void testBackgroundDaylightTheme() {
public void testBackgroundDaylightTheme() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
launchActivity();
// Type text and then press the button.
boolean isDarkTheme = ThemeChooser.getInstance(getActivity()).isDarkTheme(getActivity());
assertThat(isDarkTheme, equalTo(false));
//onView(withId(R.id.sliding_layout)).check(ViewAssertions.matches(CustomMatchers.withBackgroundColor(android.R.color.white, getActivity())));
assertFalse(isDarkTheme());
onView(withId(R.id.sliding_layout)).check(matches(withBackgroundColor(android.R.color.white, getActivity())));
}
@Test
@ -78,14 +116,12 @@ public class NightModeTest {
sleep();
switchOled();
navigateUp();
boolean isDarkTheme = ThemeChooser.getInstance(getActivity()).isDarkTheme(getActivity());
assertFalse(isDarkTheme);
assertFalse(isDarkTheme());
sleep();
//onView(withId(R.id.sliding_layout)).check(ViewAssertions.matches(CustomMatchers.withBackgroundColor(android.R.color.white, getActivity())));
assertThat(ThemeChooser.getInstance(getActivity()).OLEDActive, equalTo(false));
assertThat(ThemeChooser.getInstance(getActivity()).DarkThemeActive, equalTo(false));
assertEquals(ThemeChooser.THEME.LIGHT, getPrivateField("mSelectedTheme"));
}
@Test
@ -98,12 +134,11 @@ public class NightModeTest {
changeAppTheme(R.string.pref_display_apptheme_light);
navigateUp();
boolean isDarkTheme = ThemeChooser.getInstance(getActivity()).isDarkTheme(getActivity());
assertThat(ThemeChooser.getInstance(getActivity()).isOledMode(getActivity(), false), equalTo(false));
assertThat(isDarkTheme, equalTo(false));
assertThat(ThemeChooser.getInstance(getActivity()).OLEDActive, equalTo(false));
assertThat(ThemeChooser.getInstance(getActivity()).DarkThemeActive, equalTo(false));
sleep();
boolean isDarkTheme = isDarkTheme();
assertFalse(ThemeChooser.getInstance(getActivity()).isOledMode(getActivity(), false));
assertFalse(isDarkTheme);
assertEquals(ThemeChooser.THEME.LIGHT, getPrivateField("mSelectedTheme"));
//sleep();
}
@Test
@ -116,12 +151,11 @@ public class NightModeTest {
changeAppTheme(R.string.pref_display_apptheme_dark);
navigateUp();
sleep();
boolean isDarkTheme = ThemeChooser.getInstance(getActivity()).isDarkTheme(getActivity());
boolean isDarkTheme = isDarkTheme();
assertThat(ThemeChooser.getInstance(getActivity()).isOledMode(getActivity(), false), equalTo(false));
assertThat(isDarkTheme, equalTo(true));
assertThat(ThemeChooser.getInstance(getActivity()).OLEDActive, equalTo(false));
assertThat(ThemeChooser.getInstance(getActivity()).DarkThemeActive, equalTo(true));
sleep();
assertEquals(ThemeChooser.THEME.DARK, getPrivateField("mSelectedTheme"));
//sleep();
}
@Test
@ -135,12 +169,11 @@ public class NightModeTest {
switchOled();
navigateUp();
sleep();
boolean isDarkTheme = ThemeChooser.getInstance(getActivity()).isDarkTheme(getActivity());
assertThat(ThemeChooser.getInstance(getActivity()).isOledMode(getActivity(), false), equalTo(true));
assertThat(isDarkTheme, equalTo(true));
assertThat(ThemeChooser.getInstance(getActivity()).OLEDActive, equalTo(true));
assertThat(ThemeChooser.getInstance(getActivity()).DarkThemeActive, equalTo(true));
sleep();
boolean isDarkTheme = isDarkTheme();
assertTrue(ThemeChooser.getInstance(getActivity()).isOledMode(getActivity(), false));
assertTrue(isDarkTheme);
assertEquals(ThemeChooser.THEME.OLED, getPrivateField("mSelectedTheme"));
//sleep();
}
private void sleep() {
@ -185,25 +218,7 @@ public class NightModeTest {
.perform(click());
}
@Before
public void resetSharedPrefs() {
Context context = getInstrumentation().getTargetContext();
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
// Reset SharedPrefs
// https://developer.android.com/guide/topics/ui/settings#Defaults
mPrefs.edit()
.remove(CB_OLED_MODE)
.remove(SP_APP_THEME)
.commit();
assertThat(mPrefs.contains(SP_APP_THEME), equalTo(false));
assertThat(mPrefs.contains(CB_OLED_MODE), equalTo(false));
SharedPreferences defaultValueSp = context.getSharedPreferences(KEY_HAS_SET_DEFAULT_VALUES, Context.MODE_PRIVATE);
defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, false).commit();
}
private void launchActivity() {
@ -222,4 +237,36 @@ public class NightModeTest {
//assertFalse(ThemeChooser.getInstance(getActivity()).isDarkTheme(getActivity()));
//assertFalse(ThemeChooser.getInstance(getActivity()).isOledMode(getActivity(), true));
}
private boolean isDarkTheme() {
ThemeChooser themeChooser = ThemeChooser.getInstance(getActivity());
try {
Method method = ThemeChooser.class.getDeclaredMethod("isDarkTheme", Context.class);
method.setAccessible(true);
boolean isDarkTheme = (boolean) method.invoke(themeChooser, getActivity());
return isDarkTheme;
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
fail(e.toString() + " - " + e.getMessage());
}
return false;
}
private Object getPrivateField(String fieldName) {
ThemeChooser themeChooser = ThemeChooser.getInstance(getActivity());
try {
Field[] fields = ThemeChooser.class.getDeclaredFields();
for (Field field : fields) {
if(fieldName.equals(field.getName())) {
field.setAccessible(true);
return field.get(themeChooser);
}
}
} catch (IllegalAccessException e) {
fail(e.getMessage());
}
return null;
}
}

View file

@ -1,162 +0,0 @@
package de.luhmer.owncloudnewsreader.tests;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import de.luhmer.owncloudnewsreader.NewsReaderListActivity;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import static android.support.test.InstrumentationRegistry.registerInstance;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SyncTests {
private MockWebServer server;
//private HttpUrl baseUrl;
@Rule
public ActivityTestRule<NewsReaderListActivity> mActivityRule = new ActivityTestRule<>(
NewsReaderListActivity.class);
@Before
public void setUp() throws Exception {
registerInstance(InstrumentationRegistry.getInstrumentation(), new Bundle());
// Create a MockWebServer. These are lean enough that you can create a new
// instance for every unit test.
server = new MockWebServer();
server.start();
// Ask the server for its URL. You'll need this to make HTTP requests.
//baseUrl = server.url("/");
//HttpJsonRequest.init(mActivityRule.getActivity());
//HttpJsonRequest.getInstance().setCredentials("test", "test", baseUrl.toString());
}
/*
@Test
public void testVersionInfo() throws Exception {
// Schedule some responses.
server.enqueue(new MockResponse().setBody(getSampleVersionInfoV2()));
String versionNumber = OwnCloudReaderMethods.GetVersionNumber(baseUrl);
assertEquals("5.2.3", versionNumber);
API api = API.GetRightApiForVersion(versionNumber, baseUrl);
assertTrue(api instanceof APIv2);
}
*/
private String getSampleVersionInfoV2() {
JsonObject jVer = new JsonObject();
jVer.addProperty("version", "5.2.3");
return jVer.toString();
}
/*
@Test
public void testFeedSync() throws Exception {
JsonObject jFeed = new JsonObject();
JsonObject jF = new JsonObject();
jF.addProperty("id", "-1");
jF.addProperty("url", "");
jF.addProperty("title", "-1");
jF.addProperty("faviconLink", "-1");
jF.addProperty("added", "-1");
jF.addProperty("folderId", "-1");
jF.addProperty("ordering", "-1"); //TODO implement this field!
jF.addProperty("link", "-1");
jF.addProperty("pinned", "-1");
JsonArray jFeedArr = new JsonArray();
jFeedArr.add(jF);
jFeed.add("feeds", jFeedArr);
server.enqueue(new MockResponse().setBody(getSampleVersionInfoV2()));
server.enqueue(new MockResponse().setBody(jFeed.toString()));
String versionNumber = OwnCloudReaderMethods.GetVersionNumber(baseUrl);
API api = API.GetRightApiForVersion(versionNumber, baseUrl);
assertTrue(api instanceof APIv2);
int[] res = OwnCloudReaderMethods.GetFeeds(mActivity, api);
assertEquals(1, res[0]);
assertEquals(1, res[1]);
}
*/
@Test
public void testItemSync() {
JsonObject jItem = new JsonObject();
JsonObject jI = new JsonObject();
jI.addProperty("id", "-1");
jI.addProperty("guid", "http://grulja.wordpress.com/?p=76");
jI.addProperty("guidHash", "3059047a572cd9cd5d0bf645faffd077");
jI.addProperty("url", "http://grulja.wordpress.com/2013/04/29/plasma-nm-after-the-solid-sprint/");
jI.addProperty("title", "Plasma-nm after the solid sprint");
jI.addProperty("author", "Jan Grulich (grulja)");
jI.addProperty("pubDate", 1367270544);
jI.addProperty("body", "<p>At first I have to say...</p>");
jI.addProperty("enclosureMime", (String) null);
jI.addProperty("enclosureLink", (String) null);
jI.addProperty("feedId", "-1");
jI.addProperty("unread", true);
jI.addProperty("starred", false);
jI.addProperty("lastModified", 1367273003);
JsonArray jItemArr = new JsonArray();
jItemArr.add(jI);
jItem.add("feeds", jItemArr);
server.enqueue(new MockResponse().setBody(getSampleVersionInfoV2()));
server.enqueue(new MockResponse().setBody(jItem.toString()));
/*
String versionNumber = OwnCloudReaderMethods.GetVersionNumber(baseUrl);
API api = API.GetRightApiForVersion(versionNumber, baseUrl);
assertTrue(api instanceof APIv2);
int res2 = OwnCloudReaderMethods.GetItems(FeedItemTags.ALL, mActivity, "0", true, "0", "0", api); //TODO verify params
assertEquals(1, res2);
*/
}
@After
public void tearDown() throws Exception {
// Shut down the server. Instances cannot be reused.
server.shutdown();
}
/*
private void sleep(float seconds) {
try {
Thread.sleep((long) seconds * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
*/
}

View file

@ -1,35 +0,0 @@
package de.luhmer.owncloudnewsreader.tests;
import android.app.Application;
import android.content.SharedPreferences;
import org.mockito.Mockito;
import javax.inject.Singleton;
import dagger.Provides;
import de.luhmer.owncloudnewsreader.di.ApiModule;
import de.luhmer.owncloudnewsreader.di.ApiProvider;
import de.luhmer.owncloudnewsreader.ssl.MemorizingTrustManager;
public class TestApiModule extends ApiModule {
private Application mApplication;
public TestApiModule(Application application) {
super(application);
this.mApplication = application;
}
@Override
public SharedPreferences providesSharedPreferences() {
return Mockito.mock(SharedPreferences.class);
}
@Provides
@Singleton
public ApiProvider provideAPI(MemorizingTrustManager mtm, SharedPreferences sp) {
return new ApiProvider(mtm, sp, mApplication);
}
}

View file

@ -1,4 +1,4 @@
package de.luhmer.owncloudnewsreader.tests;
package helper;
import android.app.Activity;
import android.content.Context;
@ -8,8 +8,8 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Build;
import android.support.test.espresso.matcher.BoundedMatcher;
import android.support.v4.content.ContextCompat;
import androidx.test.espresso.matcher.BoundedMatcher;
import androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
@ -38,7 +38,7 @@ public class CustomMatchers {
Drawable drawable = view.getBackground();
Drawable otherDrawable = ContextCompat.getDrawable(view.getContext(), resourceColorId);
if (drawable instanceof ColorDrawable && otherDrawable instanceof ColorDrawable) {
if (drawable instanceof ColorDrawable) {
int colorId = ((ColorDrawable) drawable).getColor();
if(colorId == resourceColorId) {
@ -47,7 +47,9 @@ public class CustomMatchers {
error = "FAILED Got: " + colorId;
}
} else {
error = "Not color drawables!!";
Log.e(TAG, drawable.toString());
Log.e(TAG, otherDrawable.toString());
error = "Not ColorDrawable's!!";
}
return false;

View file

@ -23,21 +23,21 @@
*
*/
package de.luhmer.owncloudnewsreader.tests;
package helper;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import android.support.test.runner.lifecycle.Stage;
import androidx.test.espresso.UiController;
import androidx.test.espresso.ViewAction;
import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
import androidx.test.runner.lifecycle.Stage;
import android.view.View;
import org.hamcrest.Matcher;
import java.util.Collection;
import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
import static androidx.test.espresso.matcher.ViewMatchers.isRoot;
/**
* An Espresso ViewAction that changes the orientation of the screen

View file

@ -1,9 +1,9 @@
package de.luhmer.owncloudnewsreader.tests;
package helper;
import android.support.test.espresso.NoMatchingViewException;
import android.support.test.espresso.ViewAssertion;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import androidx.test.espresso.NoMatchingViewException;
import androidx.test.espresso.ViewAssertion;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
public class RecyclerViewAssertions implements ViewAssertion {

View file

@ -2,9 +2,9 @@ package screengrab;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.support.v4.view.GravityCompat;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;
import androidx.core.view.GravityCompat;
import org.junit.Before;
import org.junit.ClassRule;
@ -31,8 +31,10 @@ import tools.fastlane.screengrab.locale.LocaleTestRule;
*/
@RunWith(AndroidJUnit4.class)
public class ScreenshotTest {
@ClassRule
public static final LocaleTestRule localTestRule = new LocaleTestRule();
@Rule
public ActivityTestRule<NewsReaderListActivity> mActivityRule = new ActivityTestRule<>(NewsReaderListActivity.class);

View file

@ -35,7 +35,7 @@
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name"
android:launchMode="singleTop">
<intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@ -139,7 +139,7 @@
android:label="@string/auto_sync_string"
android:syncable="true" />
<provider
android:name="android.support.v4.content.FileProvider"
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
@ -205,7 +205,7 @@
</intent-filter>
</service> <!-- android:process=":podcastPlaybackService" -->
<receiver android:name="android.support.v4.media.session.MediaButtonReceiver">
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />

View file

@ -1,7 +1,7 @@
package de.luhmer.owncloudnewsreader;
import android.os.Bundle;
import android.support.annotation.Nullable;
import androidx.annotation.Nullable;
/**
* Created by benson on 11/20/15.

View file

@ -26,7 +26,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v7.widget.ViewUtils;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
@ -45,6 +44,7 @@ import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import androidx.core.view.ViewCompat;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.R;
@ -333,7 +333,7 @@ public class SubscriptionExpandableListAdapter extends BaseExpandableListAdapter
rotation = 180;
contentDescriptionId = R.string.content_desc_collapse;
} else {
if (ViewUtils.isLayoutRtl(listView)) {
if (ViewCompat.getLayoutDirection(listView) == ViewCompat.LAYOUT_DIRECTION_RTL) {
rotation = -90; // mirror for rtl layout
} else {
rotation = 90;

View file

@ -30,9 +30,7 @@ import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.design.widget.TextInputLayout;
import android.support.v4.app.DialogFragment;
import android.support.v7.app.AlertDialog;
import androidx.appcompat.app.AlertDialog;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableString;
@ -54,6 +52,7 @@ import android.widget.Switch;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.textfield.TextInputLayout;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.api.NextcloudAPI;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotInstalledException;
@ -68,6 +67,7 @@ import java.net.URL;
import javax.inject.Inject;
import androidx.fragment.app.DialogFragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.authentication.AuthenticatorActivity;

View file

@ -7,10 +7,6 @@ import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.util.Log;
import android.util.Xml;
@ -25,6 +21,8 @@ import android.widget.Toast;
import com.nbsp.materialfilepicker.ui.FilePickerActivity;
import org.json.JSONException;
import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import java.io.BufferedReader;
@ -43,6 +41,10 @@ import java.util.Map;
import javax.inject.Inject;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
@ -255,11 +257,7 @@ public class NewFeedActivity extends AppCompatActivity {
}
}
final Map<String, Object> feedMap = new HashMap<>(2);
feedMap.put("url", feedUrl);
feedMap.put("folderId", folderId);
Feed feed = mApi.getAPI().createFeed(feedMap).execute().body().get(0);
Feed feed = mApi.getAPI().createFeed(feedUrl, folderId).execute().body().get(0);
Log.v(TAG, "New Feed-ID: " + feed.getId());
}
} catch (Exception e) {
@ -336,36 +334,61 @@ public class NewFeedActivity extends AppCompatActivity {
// perform the user login attempt.
showProgress(true);
final Map<String, Object> feedMap = new HashMap<>(2);
feedMap.put("url", urlToFeed);
feedMap.put("folderId", folder.getId());
mApi.getAPI().createFeed(feedMap).enqueue(new Callback<List<Feed>>() {
mApi.getAPI().createFeed(urlToFeed, folder.getId()).enqueue(new Callback<List<Feed>>() {
@Override
public void onResponse(Call<List<Feed>> call, Response<List<Feed>> response) {
showProgress(false);
public void onResponse(Call<List<Feed>> call, final Response<List<Feed>> response) {
runOnUiThread(() -> {
showProgress(false);
if (response.isSuccessful()) {
Intent returnIntent = new Intent();
returnIntent.putExtra("success", true);
setResult(RESULT_OK,returnIntent);
if (response.isSuccessful()) {
Intent returnIntent = new Intent();
returnIntent.putExtra("success", true);
setResult(RESULT_OK, returnIntent);
finish();
} else {
mFeedUrlView.setError(getString(R.string.login_dialog_text_something_went_wrong));
mFeedUrlView.requestFocus();
}
finish();
} else {
try {
String errorMessage = response.errorBody().string();
try {
//Log.e(TAG, errorMessage);
JSONObject jObjError= new JSONObject(errorMessage);
errorMessage = jObjError.getString("message");
errorMessage = truncate(errorMessage, 150);
} catch (JSONException e) {
Log.e(TAG, "Extracting error message failed: " + errorMessage, e);
}
mFeedUrlView.setError(errorMessage);
Log.e(TAG, errorMessage);
} catch (IOException e) {
Log.e(TAG, "IOException", e);
mFeedUrlView.setError(getString(R.string.login_dialog_text_something_went_wrong));
}
mFeedUrlView.requestFocus();
}
});
}
@Override
public void onFailure(Call<List<Feed>> call, Throwable t) {
showProgress(false);
public void onFailure(Call<List<Feed>> call, final Throwable t) {
runOnUiThread(() -> {
showProgress(false);
mFeedUrlView.setError(getString(R.string.login_dialog_text_something_went_wrong) + " - " + OkHttpSSLClient.HandleExceptions((Exception) t).getMessage());
mFeedUrlView.requestFocus();
mFeedUrlView.setError(getString(R.string.login_dialog_text_something_went_wrong) + " - " + OkHttpSSLClient.HandleExceptions((Exception) t).getMessage());
mFeedUrlView.requestFocus();
});
}
});
}
}
public static String truncate(String str, int len) {
if (str.length() > len) {
return str.substring(0, len) + "...";
} else {
return str;
}
}
private boolean isUrlValid(String url) {
try {
new URL(url);

View file

@ -29,15 +29,10 @@ import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.customtabs.CustomTabsIntent;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.support.v7.widget.Toolbar;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import androidx.appcompat.widget.Toolbar;
import android.text.Html;
import android.util.Log;
import android.util.SparseArray;
@ -52,12 +47,17 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm.SORT_DIRECTION;
import de.luhmer.owncloudnewsreader.database.model.RssItem;
import de.luhmer.owncloudnewsreader.helper.PostDelayHandler;
import de.luhmer.owncloudnewsreader.model.PodcastItem;
import de.luhmer.owncloudnewsreader.model.TTSItem;
import de.luhmer.owncloudnewsreader.widget.WidgetProvider;
@ -66,12 +66,12 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
private static final String TAG = NewsDetailActivity.class.getCanonicalName();
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide
* The {@link PagerAdapter} that will provide
* fragments for each of the sections. We use a
* {@link android.support.v4.app.FragmentPagerAdapter} derivative, which
* {@link FragmentPagerAdapter} derivative, which
* will keep every loaded fragment in memory. If this becomes too memory
* intensive, it may be best to switch to a
* {@link android.support.v4.app.FragmentStatePagerAdapter}.
* {@link FragmentStatePagerAdapter}.
*/
private SectionsPagerAdapter mSectionsPagerAdapter;
protected @BindView(R.id.toolbar) Toolbar toolbar;
@ -169,7 +169,7 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
super.onDestroy();
}
private OnPageChangeListener onPageChangeListener = new OnPageChangeListener() {
private ViewPager.OnPageChangeListener onPageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int pos) {

View file

@ -28,11 +28,8 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.customtabs.CustomTabsIntent;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import android.util.Log;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@ -58,6 +55,9 @@ import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.adapter.ProgressBarWebChromeClient;
@ -269,11 +269,12 @@ public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Li
mTvOfflineVersion.setVisibility(View.GONE);
switch (selectedBrowser) {
case 0: // Custom Tabs
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.setToolbarColor(ContextCompat.getColor(getActivity(), R.color.colorPrimary));
builder.setShowTitle(true);
builder.setStartAnimations(getActivity(), R.anim.slide_in_right, R.anim.slide_out_left);
builder.setExitAnimations(getActivity(), R.anim.slide_in_left, R.anim.slide_out_right);
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder()
.setToolbarColor(ContextCompat.getColor(getActivity(), R.color.colorPrimary))
.setShowTitle(true)
.setStartAnimations(getActivity(), R.anim.slide_in_right, R.anim.slide_out_left)
.setExitAnimations(getActivity(), R.anim.slide_in_left, R.anim.slide_out_right)
.addDefaultShareMenuItem();
builder.build().launchUrl(getActivity(), Uri.parse(url));
return true;
case 1: // External Browser

View file

@ -16,8 +16,7 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.DialogFragment;
import androidx.core.app.ActivityCompat;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -41,10 +40,11 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import androidx.fragment.app.DialogFragment;
import de.luhmer.owncloudnewsreader.helper.NewsFileUtils;
import de.luhmer.owncloudnewsreader.notification.NextcloudNotificationManager;
import static android.support.v4.content.PermissionChecker.checkSelfPermission;
import static androidx.core.content.PermissionChecker.checkSelfPermission;
public class NewsDetailImageDialogFragment extends DialogFragment {

View file

@ -10,6 +10,8 @@ import de.luhmer.owncloudnewsreader.helper.ForegroundListener;
public class NewsReaderApplication extends Application {
protected AppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
@ -33,13 +35,7 @@ public class NewsReaderApplication extends Application {
//mAppComponent = DaggerAppComponent.create();
}
private AppComponent mAppComponent;
public AppComponent getAppComponent() {
return mAppComponent;
}
public void setAppComponent(AppComponent appComponent) {
this.mAppComponent = appComponent;
}
}

View file

@ -32,15 +32,12 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import androidx.core.content.ContextCompat;
import androidx.core.view.GestureDetectorCompat;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.ItemTouchHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
@ -53,6 +50,9 @@ import android.widget.Toast;
import java.util.List;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.adapter.NewsListRecyclerAdapter;
@ -291,7 +291,7 @@ public class NewsReaderDetailFragment extends Fragment {
ButterKnife.bind(this, rootView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), RecyclerView.VERTICAL, false));
recyclerView.setItemAnimator(new DefaultItemAnimator());
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new NewsReaderItemTouchHelperCallback());

View file

@ -37,22 +37,13 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.design.widget.Snackbar;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.ViewDragHelper;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
@ -61,6 +52,7 @@ import android.widget.SearchView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.snackbar.Snackbar;
import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.api.NextcloudAPI;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
@ -82,6 +74,14 @@ import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.TimeUnit;
import androidx.customview.widget.ViewDragHelper;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.ListView.SubscriptionExpandableListAdapter;
@ -510,7 +510,7 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements
// Setting android:TextColor to #000 in the light theme results in black on black
// text on the Snackbar, set the text back to white,
// TODO: find a cleaner way to do this
TextView textView = snackbar.getView().findViewById(android.support.design.R.id.snackbar_text);
TextView textView = snackbar.getView().findViewById(com.google.android.material.R.id.snackbar_text);
textView.setTextColor(Color.WHITE);
snackbar.show();
}
@ -918,15 +918,14 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements
@Override
protected void onActivityResult(int requestCode, int resultCode, final Intent data) {
super.onActivityResult(requestCode, resultCode, data);
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK) {
UpdateListView();
getSlidingListFragment().ListViewNotifyDataSetChanged();
if(resultCode == RESULT_OK) {
UpdateListView();
getSlidingListFragment().ListViewNotifyDataSetChanged();
}
if(requestCode == RESULT_SETTINGS)
{
if(requestCode == RESULT_SETTINGS) {
//Update settings of image Loader
mApi.initApi(new NextcloudAPI.ApiConnectedListener() {
@Override
@ -984,7 +983,7 @@ public class NewsReaderListActivity extends PodcastFragmentActivity implements
}
private void ensureCorrectTheme(Intent data) {
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences mPrefs = PreferenceManager.getDefaultSharedPreferences(this);
String oldListLayout = data.getStringExtra(SettingsActivity.SP_FEED_LIST_LAYOUT);
String newListLayout = mPrefs.getString(SettingsActivity.SP_FEED_LIST_LAYOUT,"0");

View file

@ -5,7 +5,6 @@ import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
@ -28,6 +27,7 @@ import java.util.Map;
import javax.inject.Inject;
import androidx.fragment.app.DialogFragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm;
@ -42,7 +42,7 @@ import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
public class NewsReaderListDialogFragment extends DialogFragment{
public class NewsReaderListDialogFragment extends DialogFragment {
protected @Inject ApiProvider mApi;

View file

@ -25,7 +25,6 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Base64;
import android.util.Log;
import android.util.TypedValue;
@ -50,6 +49,7 @@ import java.io.Serializable;
import javax.inject.Inject;
import androidx.fragment.app.Fragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.ListView.SubscriptionExpandableListAdapter;

View file

@ -4,8 +4,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.AlertDialog;
import androidx.appcompat.app.AlertDialog;
import android.text.InputFilter;
import android.util.Log;
import android.view.ContextThemeWrapper;
@ -38,6 +37,7 @@ import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Locale;
import androidx.fragment.app.Fragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

View file

@ -11,13 +11,13 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.view.GravityCompat;
import android.support.v7.app.AppCompatActivity;
import androidx.core.view.GravityCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import android.util.TypedValue;
import android.view.SurfaceView;

View file

@ -42,15 +42,14 @@ import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.TwoStatePreference;
import android.provider.Settings;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.AppCompatCheckedTextView;
import android.support.v7.widget.AppCompatEditText;
import android.support.v7.widget.AppCompatRadioButton;
import android.support.v7.widget.AppCompatSpinner;
import android.support.v7.widget.Toolbar;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.appcompat.widget.AppCompatCheckBox;
import androidx.appcompat.widget.AppCompatCheckedTextView;
import androidx.appcompat.widget.AppCompatEditText;
import androidx.appcompat.widget.AppCompatRadioButton;
import androidx.appcompat.widget.AppCompatSpinner;
import androidx.appcompat.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
@ -59,6 +58,8 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;
import com.google.android.material.appbar.AppBarLayout;
import java.lang.reflect.Field;
import java.util.List;

View file

@ -7,9 +7,8 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@ -18,6 +17,7 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import androidx.fragment.app.Fragment;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.authentication.AccountGeneral;

View file

@ -5,10 +5,11 @@ import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private Drawable mDivider;
@ -40,7 +41,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration {
return;
if (!(parent.getLayoutManager() instanceof LinearLayoutManager) ||
((LinearLayoutManager)parent.getLayoutManager()).getOrientation() != LinearLayoutManager.VERTICAL) {
((LinearLayoutManager)parent.getLayoutManager()).getOrientation() != RecyclerView.VERTICAL) {
throw new IllegalStateException(
"DividerItemDecoration can only be used with a vertical LinearLayoutManager.");
}

View file

@ -3,9 +3,6 @@ package de.luhmer.owncloudnewsreader.adapter;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@ -18,6 +15,9 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import de.luhmer.owncloudnewsreader.R;
import de.luhmer.owncloudnewsreader.SettingsActivity;
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm;

View file

@ -1,9 +1,9 @@
package de.luhmer.owncloudnewsreader.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ProgressBar;
import androidx.recyclerview.widget.RecyclerView;
import de.luhmer.owncloudnewsreader.R;
public class ProgressViewHolder extends RecyclerView.ViewHolder {

View file

@ -5,9 +5,8 @@ import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Typeface;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
@ -30,6 +29,7 @@ import org.greenrobot.eventbus.Subscribe;
import java.util.List;
import java.util.regex.Pattern;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
import de.luhmer.owncloudnewsreader.R;

View file

@ -1,7 +1,7 @@
package de.luhmer.owncloudnewsreader.authentication;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatActivity;
import de.luhmer.owncloudnewsreader.NewsReaderListActivity;
import de.luhmer.owncloudnewsreader.R;

View file

@ -20,7 +20,7 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.support.customtabs.CustomTabsService;
import androidx.browser.customtabs.CustomTabsService;
import android.text.TextUtils;
import android.util.Log;

View file

@ -3,7 +3,7 @@ package de.luhmer.owncloudnewsreader.di;
import android.app.Application;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.annotation.VisibleForTesting;
import androidx.annotation.VisibleForTesting;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;

View file

@ -2,7 +2,7 @@ package de.luhmer.owncloudnewsreader.di;
import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import androidx.annotation.NonNull;
import android.util.Log;
import com.nextcloud.android.sso.api.NextcloudAPI;
@ -14,6 +14,7 @@ import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
import androidx.annotation.VisibleForTesting;
import de.luhmer.owncloudnewsreader.SettingsActivity;
import de.luhmer.owncloudnewsreader.helper.GsonConfig;
import de.luhmer.owncloudnewsreader.reader.OkHttpImageDownloader;
@ -35,9 +36,9 @@ public class ApiProvider {
private static final String TAG = ApiProvider.class.getCanonicalName();
private final MemorizingTrustManager mMemorizingTrustManager;
private final SharedPreferences mPrefs;
private API mApi;
private Context context;
protected final SharedPreferences mPrefs;
protected Context context;
protected API mApi;
public ApiProvider(MemorizingTrustManager mtm, SharedPreferences sp, Context context) {
@ -89,7 +90,7 @@ public class ApiProvider {
mApi = retrofit.create(API.class);
}
private void initSsoApi(final NextcloudAPI.ApiConnectedListener callback) {
protected void initSsoApi(final NextcloudAPI.ApiConnectedListener callback) {
try {
SingleSignOnAccount ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context);
NextcloudAPI nextcloudAPI = new NextcloudAPI(context, ssoAccount, GsonConfig.GetGson(), callback);
@ -125,4 +126,9 @@ public class ApiProvider {
public API getAPI() {
return mApi;
}
@VisibleForTesting
public void setAPI(API api) {
this.mApi = api;
}
}

View file

@ -5,7 +5,7 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Build;
import android.support.annotation.WorkerThread;
import androidx.annotation.WorkerThread;
import android.text.TextUtils;
import android.webkit.WebResourceResponse;

View file

@ -22,11 +22,11 @@ package de.luhmer.owncloudnewsreader.helper;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;

View file

@ -24,6 +24,8 @@ import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
import androidx.appcompat.widget.AppCompatTextView;
/**
* Text view that auto adjusts text size to fit within the view.
* If the text size equals the minimum text size and still does not
@ -32,7 +34,7 @@ import android.widget.TextView;
* @author Chase Colburn
* @since Apr 4, 2011
*/
public class AutoResizeTextView extends TextView {
public class AutoResizeTextView extends AppCompatTextView {
// Minimum text size for this text view
public static final float MIN_TEXT_SIZE = 20;

View file

@ -23,8 +23,8 @@ package de.luhmer.owncloudnewsreader.helper;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.content.ContextCompat;
import android.support.v7.graphics.Palette;
import androidx.core.content.ContextCompat;
import androidx.palette.graphics.Palette;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;

View file

@ -26,7 +26,7 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatDelegate;
import androidx.appcompat.app.AppCompatDelegate;
import android.util.Log;
import de.luhmer.owncloudnewsreader.R;

View file

@ -12,15 +12,17 @@ import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.support.v4.app.NotificationCompat;
import android.support.v4.content.FileProvider;
import androidx.core.app.NotificationCompat;
import androidx.core.content.FileProvider;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaButtonReceiver;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import androidx.media.session.MediaButtonReceiver;
import androidx.media.app.NotificationCompat.MediaStyle;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.ImageSize;
@ -199,7 +201,7 @@ public class NextcloudNotificationManager {
boolean isPlaying = controller.getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING;
builder.addAction(getPlayPauseAction(context, isPlaying));
builder.setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle()
builder.setStyle(new MediaStyle()
//.setShowActionsInCompactView(0) // show only play/pause in compact view
.setMediaSession(mediaSession.getSessionToken())
.setShowCancelButton(true)

View file

@ -15,6 +15,8 @@ import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.PUT;
@ -54,8 +56,9 @@ public interface API {
@POST("folders")
Call<List<Folder>> createFolder(@Body Map<String, Object> folderMap);
@FormUrlEncoded
@POST("feeds")
Call<List<Feed>> createFeed(@Body Map<String, Object> feedMap);
Call<List<Feed>> createFeed(@Field("url") String url, @Field("folderId") Long parentFolderID);
@PUT("feeds/{feedId}/rename")

View file

@ -24,9 +24,9 @@ package de.luhmer.owncloudnewsreader.services;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.support.annotation.NonNull;
import android.support.v4.app.JobIntentService;
import android.support.v4.app.NotificationCompat;
import androidx.annotation.NonNull;
import androidx.core.app.JobIntentService;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import com.nostra13.universalimageloader.core.ImageLoader;

View file

@ -8,7 +8,7 @@ import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.support.v4.app.NotificationCompat;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import android.webkit.ConsoleMessage;
import android.webkit.ValueCallback;

View file

@ -6,7 +6,7 @@ import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

View file

@ -8,12 +8,12 @@ import android.media.AudioManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaBrowserServiceCompat;
import androidx.media.MediaBrowserServiceCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaButtonReceiver;
import androidx.media.session.MediaButtonReceiver;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.telephony.PhoneStateListener;

View file

@ -25,7 +25,7 @@ import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.content.Context;
import android.content.Intent;
import android.support.v4.app.JobIntentService;
import androidx.core.app.JobIntentService;
import android.util.Log;
import java.io.IOException;

View file

@ -31,9 +31,9 @@ import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import androidx.fragment.app.DialogFragment;
import de.luhmer.owncloudnewsreader.R;
public class MemorizingDialogFragment extends DialogFragment

View file

@ -41,9 +41,7 @@ import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.NotificationCompat;
import androidx.core.app.NotificationCompat;
import android.util.Log;
import android.util.SparseArray;
@ -64,6 +62,8 @@ import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import de.luhmer.owncloudnewsreader.R;
/**

View file

@ -3,6 +3,7 @@ package de.luhmer.owncloudnewsreader.ssl;
import android.annotation.SuppressLint;
import android.content.SharedPreferences;
import android.os.Build;
import androidx.annotation.RequiresApi;
import com.google.gson.JsonParseException;
@ -29,7 +30,6 @@ import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.internal.Util;
import okhttp3.logging.HttpLoggingInterceptor;
/**
@ -38,6 +38,7 @@ import okhttp3.logging.HttpLoggingInterceptor;
public class OkHttpSSLClient {
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
public static OkHttpClient GetSslClient(HttpUrl baseUrl, String username, String password, SharedPreferences sp, MemorizingTrustManager mtm) {
// set location of the keystore
MemorizingTrustManager.setKeyStoreFile("private", "sslkeys.bks");
@ -48,7 +49,7 @@ public class OkHttpSSLClient {
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.MINUTES)
.addInterceptor(new AuthorizationInterceptor(baseUrl, Credentials.basic(username, password, Util.UTF_8)))
.addInterceptor(new AuthorizationInterceptor(baseUrl, Credentials.basic(username, password, java.nio.charset.StandardCharsets.UTF_8)))
.addInterceptor(interceptor);
// register MemorizingTrustManager for HTTPS

View file

@ -4,7 +4,7 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import androidx.core.app.NotificationCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;

View file

@ -10,7 +10,7 @@
sothree:umanoParallaxOffset="100dp"
sothree:umanoShadowHeight="4dp"> <!-- sothree:dragView="@+id/name" -->
<android.support.design.widget.CoordinatorLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -53,7 +53,7 @@
</de.luhmer.owncloudnewsreader.view.ZoomableRelativeLayout>
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<FrameLayout
android:id="@+id/podcast_frame"

View file

@ -1,4 +1,4 @@
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent"
@ -100,4 +100,4 @@
android:id="@+id/toolbar_layout"
layout="@layout/toolbar_layout" />
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -1,4 +1,4 @@
<android.support.design.widget.CoordinatorLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
@ -17,7 +17,7 @@
sothree:umanoParallaxOffset="100dp"
sothree:umanoDragView="@+id/name">
<android.support.v4.view.ViewPager
<androidx.viewpager.widget.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -39,7 +39,7 @@
android:paddingTop="4dp"
android:textColor="#fff" />
-->
</android.support.v4.view.ViewPager>
</androidx.viewpager.widget.ViewPager>
<FrameLayout
android:id="@+id/podcast_frame"
@ -74,4 +74,4 @@
android:layoutDirection="ltr"
style="?android:attr/progressBarStyleHorizontal" />
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -10,12 +10,12 @@
sothree:umanoParallaxOffset="100dp"
sothree:umanoShadowHeight="4dp"> <!-- sothree:dragView="@+id/name" -->
<android.support.v4.widget.DrawerLayout
<androidx.drawerlayout.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.CoordinatorLayout
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -63,7 +63,7 @@
</android.support.design.widget.CoordinatorLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
<FrameLayout
android:id="@+id/left_drawer"
@ -71,7 +71,7 @@
android:layout_height="match_parent"
android:layout_gravity="start" />
</android.support.v4.widget.DrawerLayout>
</androidx.drawerlayout.widget.DrawerLayout>
<FrameLayout
android:id="@+id/podcast_frame"

View file

@ -20,7 +20,7 @@
android:text="Use single sign on" />
<android.support.design.widget.TextInputLayout
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/username_container"
@ -36,9 +36,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
<android.support.design.widget.TextInputLayout
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/username_container"
@ -56,9 +56,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
<android.support.design.widget.TextInputLayout
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/url_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -78,7 +78,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</android.support.design.widget.TextInputLayout>
</com.google.android.material.textfield.TextInputLayout>
<ImageView
android:id="@+id/imgView_ShowPassword"

View file

@ -4,19 +4,19 @@
android:layout_height="match_parent"
tools:showIn="@layout/activity_newsreader">
<android.support.v4.widget.SwipeRefreshLayout
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipeRefresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/list"
style="?android:attr/textAppearanceLarge"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical" />
</android.support.v4.widget.SwipeRefreshLayout>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
<TextView
android:id="@+id/tv_no_items_available"

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
<androidx.cardview.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
@ -142,4 +142,4 @@
</RelativeLayout>
</LinearLayout>
</android.support.v7.widget.CardView>
</androidx.cardview.widget.CardView>

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout
<com.google.android.material.appbar.AppBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/ToolbarTheme" />
</android.support.design.widget.AppBarLayout>
</com.google.android.material.appbar.AppBarLayout>

View file

@ -20,4 +20,6 @@
ANDROID_BUILD_MIN_SDK_VERSION=17
ANDROID_BUILD_TARGET_SDK_VERSION=28
ANDROID_BUILD_TOOLS_VERSION=28.0.3
ANDROID_BUILD_SDK_VERSION=28
ANDROID_BUILD_SDK_VERSION=28
android.useAndroidX=true
android.enableJetifier=true