diff --git a/build.gradle b/build.gradle index 99954046da0..e8589a6c427 100644 --- a/build.gradle +++ b/build.gradle @@ -4,6 +4,7 @@ buildscript { kotlinVersion = '1.3.21' archLifecycleVersion = '2.0.0' roomVersion = '2.0.0' + koinVersion = '2.0.1' // Testing junitVersion = "4.12" diff --git a/owncloudApp/build.gradle b/owncloudApp/build.gradle index 8b7542cef5e..0be09036178 100644 --- a/owncloudApp/build.gradle +++ b/owncloudApp/build.gradle @@ -36,12 +36,12 @@ dependencies { androidTestImplementation 'androidx.test:runner:1.1.1' // Espresso core androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + // Espresso contrib + androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.1' // Espresso intents androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.1' // Espresso web androidTestImplementation 'androidx.test.espresso:espresso-web:3.1.1' - // Espresso intents - androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0' // UIAutomator - for cross-app UI tests, and to grant screen is turned on in Espresso tests androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' // fix conflict in dependencies; see http://g.co/androidstudio/app-test-app-conflict for details @@ -76,6 +76,9 @@ dependencies { // Room implementation "androidx.room:room-runtime:$roomVersion" kapt "androidx.room:room-compiler:$roomVersion" + + // Koin dependency injector + implementation "org.koin:koin-androidx-viewmodel:$koinVersion" } tasks.withType(Test) { @@ -172,7 +175,7 @@ android { testOptions { unitTests.returnDefaultValues = true - animationsDisabled = false + animationsDisabled = true } } diff --git a/owncloudApp/src/test/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSourceTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSourceTest.kt similarity index 95% rename from owncloudApp/src/test/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSourceTest.kt rename to owncloudApp/src/androidTest/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSourceTest.kt index 00e288f397f..85ef1371ad3 100644 --- a/owncloudApp/src/test/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSourceTest.kt +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSourceTest.kt @@ -21,6 +21,7 @@ package com.owncloud.android.capabilities.datasource import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.MutableLiveData +import androidx.test.platform.app.InstrumentationRegistry import com.owncloud.android.capabilities.db.OCCapability import com.owncloud.android.capabilities.db.OCCapabilityDao import com.owncloud.android.db.OwncloudDatabase @@ -73,7 +74,9 @@ class OCLocalCapabilitiesDataSourceTest { newCapabilityAsLiveData ) - ocLocalCapabilitiesDataSource = OCLocalCapabilitiesDataSource(ocCapabilityDao) + val context = InstrumentationRegistry.getInstrumentation().targetContext + + ocLocalCapabilitiesDataSource = OCLocalCapabilitiesDataSource(context, ocCapabilityDao) } @Test diff --git a/owncloudApp/src/test/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModelTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModelTest.kt similarity index 89% rename from owncloudApp/src/test/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModelTest.kt rename to owncloudApp/src/androidTest/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModelTest.kt index 2f162bf4eca..4110a56138b 100644 --- a/owncloudApp/src/test/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModelTest.kt +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModelTest.kt @@ -22,6 +22,7 @@ package com.owncloud.android.capabilities.viewmodel import android.accounts.Account import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.MutableLiveData +import androidx.test.platform.app.InstrumentationRegistry import com.owncloud.android.capabilities.db.OCCapability import com.owncloud.android.capabilities.repository.OCCapabilityRepository import com.owncloud.android.utils.TestUtil @@ -38,7 +39,6 @@ import org.mockito.Mockito.mock @RunWith(JUnit4::class) class OCCapabilityViewModelTest { private var testAccount: Account = TestUtil.createAccount("admin@server", "test") - private lateinit var capability: OCCapability @Rule @@ -54,18 +54,20 @@ class OCCapabilityViewModelTest { fun loadCapability() { val ocCapabilityRepository = mock(OCCapabilityRepository::class.java) - val capabilityResourceAsLiveData: MutableLiveData> = MutableLiveData() - capabilityResourceAsLiveData.value = Resource.success(capability) - `when`( ocCapabilityRepository.loadCapabilityForAccount( "admin@server" ) ).thenReturn( - capabilityResourceAsLiveData + MutableLiveData>().apply { + value = Resource.success(capability) + } ) + val context = InstrumentationRegistry.getInstrumentation().targetContext + val ocCapabilityViewModel = OCCapabilityViewModel( + context, account = testAccount, capabilityRepository = ocCapabilityRepository ) diff --git a/owncloudApp/src/test/java/com/owncloud/android/shares/datasource/OCLocalShareDataSourceTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/datasource/OCLocalShareDataSourceTest.kt similarity index 96% rename from owncloudApp/src/test/java/com/owncloud/android/shares/datasource/OCLocalShareDataSourceTest.kt rename to owncloudApp/src/androidTest/java/com/owncloud/android/shares/datasource/OCLocalShareDataSourceTest.kt index 17677685854..71113eb944a 100644 --- a/owncloudApp/src/test/java/com/owncloud/android/shares/datasource/OCLocalShareDataSourceTest.kt +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/datasource/OCLocalShareDataSourceTest.kt @@ -21,6 +21,7 @@ package com.owncloud.android.shares.datasource import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.MutableLiveData +import androidx.test.platform.app.InstrumentationRegistry import com.owncloud.android.db.OwncloudDatabase import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.shares.db.OCShare @@ -115,7 +116,9 @@ class OCLocalDataSourceTest { 1 ) - ocLocalSharesDataSource = OCLocalSharesDataSource(ocSharesDao) + val context = InstrumentationRegistry.getInstrumentation().targetContext + + ocLocalSharesDataSource = OCLocalSharesDataSource(context, ocSharesDao) } @Test diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/db/OCShareDaoTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/db/OCShareDaoTest.kt index a6622797c90..a87f8ed15c3 100644 --- a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/db/OCShareDaoTest.kt +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/db/OCShareDaoTest.kt @@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry import com.owncloud.android.db.OwncloudDatabase import com.owncloud.android.lib.resources.shares.ShareType +import com.owncloud.android.shares.db.OCShareDao import com.owncloud.android.utils.LiveDataTestUtil.getValue import com.owncloud.android.utils.TestUtil import junit.framework.Assert.assertEquals diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/ShareFileFragmentTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/ShareFileFragmentTest.kt index b0268cc65b0..e9c91ce117a 100644 --- a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/ShareFileFragmentTest.kt +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/ShareFileFragmentTest.kt @@ -23,6 +23,7 @@ import android.accounts.Account import androidx.test.espresso.Espresso.onView import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.hasSibling import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId @@ -102,6 +103,12 @@ class ShareFileFragmentTest { fun showPublicShares() { loadShareFileFragment() onView(withText("Image link")).check(matches(isDisplayed())) + onView(withText("Image link")).check(matches(hasSibling(withId(R.id.getPublicLinkButton)))) + .check(matches(isDisplayed())) + onView(withText("Image link")).check(matches(hasSibling(withId(R.id.deletePublicLinkButton)))) + .check(matches(isDisplayed())) + onView(withText("Image link")).check(matches(hasSibling(withId(R.id.editPublicLinkButton)))) + .check(matches(isDisplayed())) onView(withText("Image link 2")).check(matches(isDisplayed())) onView(withText("Image link 3")).check(matches(isDisplayed())) } diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/CreatePublicShareTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/CreatePublicShareTest.kt new file mode 100644 index 00000000000..9e6c06b41e9 --- /dev/null +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/CreatePublicShareTest.kt @@ -0,0 +1,373 @@ +/** + * ownCloud Android client application + * + * @author David González Verdugo + * Copyright (C) 2019 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.shares.ui.usecases + +import android.accounts.Account +import android.accounts.AccountManager +import android.content.Context +import android.content.Intent +import android.os.Parcelable +import androidx.lifecycle.MutableLiveData +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import com.owncloud.android.R +import com.owncloud.android.authentication.AccountAuthenticator.KEY_AUTH_TOKEN_TYPE +import com.owncloud.android.capabilities.db.OCCapability +import com.owncloud.android.capabilities.viewmodel.OCCapabilityViewModel +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.accounts.AccountUtils +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.status.CapabilityBooleanType +import com.owncloud.android.lib.resources.status.OwnCloudVersion +import com.owncloud.android.shares.db.OCShare +import com.owncloud.android.shares.ui.ShareActivity +import com.owncloud.android.shares.viewmodel.OCShareViewModel +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.utils.AccountsManager +import com.owncloud.android.utils.TestUtil +import com.owncloud.android.vo.Resource +import org.junit.AfterClass +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import org.mockito.Mockito.spy + +class CreatePublicShareTest { + @Rule + @JvmField + val activityRule = ActivityTestRule( + ShareActivity::class.java, + true, + false + ) + + private lateinit var file: OCFile + + private val publicShares = arrayListOf( + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "image.jpg link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "image.jpg link (2)", + shareLink = "http://server:port/s/2" + ), + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "image.jpg link (3)", + shareLink = "http://server:port/s/3" + ) + ) + + private val capabilitiesLiveData = MutableLiveData>() + private val sharesLiveData = MutableLiveData>>() + + private val ocCapabilityViewModel = mock(OCCapabilityViewModel::class.java) + private val ocShareViewModel = mock(OCShareViewModel::class.java) + + companion object { + private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext + private val account = Account("admin", "owncloud") + + @BeforeClass + @JvmStatic + fun init() { + addAccount() + } + + @AfterClass + @JvmStatic + fun cleanUp() { + AccountsManager.deleteAllAccounts(targetContext) + } + + private fun addAccount() { + // obtaining an AccountManager instance + val accountManager = AccountManager.get(targetContext) + + accountManager.addAccountExplicitly(account, "a", null) + + // include account version, user, server version and token with the new account + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_VERSION, + OwnCloudVersion("10.2").toString() + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_BASE_URL, + "serverUrl:port" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_DISPLAY_NAME, + "admin" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION, + "1" + ) + + accountManager.setAuthToken( + account, + KEY_AUTH_TOKEN_TYPE, + "AUTH_TOKEN" + ) + } + } + + @Before + fun setUp() { + val intent = spy(Intent::class.java) + + file = getOCFileForTesting("image.jpg") + + `when`(intent.getParcelableExtra(FileActivity.EXTRA_FILE) as? Parcelable).thenReturn(file) + intent.putExtra(FileActivity.EXTRA_FILE, file) + + `when`(ocCapabilityViewModel.getCapabilityForAccount(false)).thenReturn(capabilitiesLiveData) + `when`(ocCapabilityViewModel.getCapabilityForAccount(true)).thenReturn(capabilitiesLiveData) + `when`(ocShareViewModel.getSharesForFile()).thenReturn(sharesLiveData) + + stopKoin() + + startKoin { + androidContext(ApplicationProvider.getApplicationContext()) + modules( + module(override = true) { + viewModel { + ocCapabilityViewModel + } + viewModel { + ocShareViewModel + } + } + ) + } + + activityRule.launchActivity(intent) + } + + @Test + fun createPublicShareWithNoPublicSharesYet() { + loadCapabilitiesSuccessfully() + loadSharesSuccessfully(arrayListOf()) + + // Create share + onView(withId(R.id.addPublicLinkButton)).perform(click()) + + val newPublicShare = publicShares[0] + savePublicShare(newPublicShare) + + // New share properly created + sharesLiveData.postValue( + Resource.success( + arrayListOf(newPublicShare) + ) + ) + + // Check whether the dialog to create the public share has been properly closed + onView(withText(R.string.share_via_link_create_title)).check(doesNotExist()) + onView(withText(newPublicShare.name)).check(matches(isDisplayed())) + } + + @Test + fun createPublicShareWithAlreadyExistingShares() { + loadCapabilitiesSuccessfully() + val existingPublicShares = publicShares.take(2) as ArrayList + loadSharesSuccessfully( + existingPublicShares + ) + + onView(withId(R.id.addPublicLinkButton)).perform(click()) + + val newPublicShare = publicShares[2] + savePublicShare(newPublicShare) + + // New share properly created + sharesLiveData.postValue( + Resource.success( + publicShares + ) + ) + + // Check whether the dialog to create the public share has been properly closed + onView(withText(R.string.share_via_link_create_title)).check(doesNotExist()) + onView(withText(newPublicShare.name)).check(matches(isDisplayed())) + } + + @Test + fun createMultiplePublicShares() { + loadCapabilitiesSuccessfully() + loadSharesSuccessfully(arrayListOf()) + + /** + * 1st public share + */ + onView(withId(R.id.addPublicLinkButton)).perform(click()) + + val newPublicShare1 = publicShares[0] + savePublicShare(newPublicShare1) + + // New share properly created + sharesLiveData.postValue( + Resource.success( + arrayListOf(newPublicShare1) + ) + ) + + // Check whether the dialog to create the public share has been properly closed + onView(withText(R.string.share_via_link_create_title)).check(doesNotExist()) + onView(withText(newPublicShare1.name)).check(matches(isDisplayed())) + + /** + * 2nd public share + */ + onView(withId(R.id.addPublicLinkButton)).perform(click()) + + val newPublicShare2 = publicShares[1] + savePublicShare(newPublicShare2) + + // New share properly created + sharesLiveData.postValue( + Resource.success( + publicShares.take(2) + ) + ) + + // Check whether the dialog to create the public share has been properly closed + onView(withText(R.string.share_via_link_create_title)).check(doesNotExist()) + onView(withText(newPublicShare2.name)).check(matches(isDisplayed())) + + /** + * 3rd public share + */ + onView(withId(R.id.addPublicLinkButton)).perform(click()) + + val newPublicShare3 = publicShares[2] + savePublicShare(newPublicShare3) + + // New share properly created + sharesLiveData.postValue( + Resource.success( + publicShares + ) + ) + + // Check whether the dialog to create the public share has been properly closed + onView(withText(R.string.share_via_link_create_title)).check(doesNotExist()) + onView(withText(newPublicShare3.name)).check(matches(isDisplayed())) + } + + @Test + fun createShareLoading() { + loadCapabilitiesSuccessfully() + loadSharesSuccessfully(arrayListOf()) + + onView(withId(R.id.addPublicLinkButton)).perform(click()) + + savePublicShare(publicShares[0], Resource.loading()) + + onView(withText(R.string.common_loading)).check(matches(isDisplayed())) + } + + @Test + fun createShareError() { + loadCapabilitiesSuccessfully() + loadSharesSuccessfully(arrayListOf()) + + onView(withId(R.id.addPublicLinkButton)).perform(click()) + + savePublicShare( + publicShares[0], + Resource.error( + RemoteOperationResult.ResultCode.FORBIDDEN, + exception = Exception("Error when retrieving shares") + ) + ) + + onView(withText(R.string.share_link_file_error)).check(matches(isDisplayed())) + } + + private fun getOCFileForTesting(name: String = "default") = OCFile("/Photos").apply { + availableOfflineStatus = OCFile.AvailableOfflineStatus.NOT_AVAILABLE_OFFLINE + fileName = name + fileId = 9456985479 + remoteId = "1" + privateLink = "private link" + } + + private fun loadCapabilitiesSuccessfully( + capability: OCCapability = TestUtil.createCapability( + versionString = "10.1.1", + sharingPublicMultiple = CapabilityBooleanType.TRUE.value + ) + ) { + capabilitiesLiveData.postValue( + Resource.success( + capability + ) + ) + } + + private fun loadSharesSuccessfully(shares: ArrayList = publicShares) { + sharesLiveData.postValue(Resource.success(shares)) + } + + private fun savePublicShare(newShare: OCShare, resource: Resource = Resource.success()) { + `when`( + ocShareViewModel.insertPublicShareForFile( + 1, + newShare.name!!, + "", + -1, + false + ) + ).thenReturn( + MutableLiveData>().apply { + postValue(resource) + } + ) + + onView(withId(R.id.saveButton)).perform(click()) + } +} diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/DeletePublicShareTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/DeletePublicShareTest.kt new file mode 100644 index 00000000000..eb98c672475 --- /dev/null +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/DeletePublicShareTest.kt @@ -0,0 +1,318 @@ +/** + * ownCloud Android client application + * + * @author Jesus Recio (@jesmrec) + * @author David González (@davigonz) + * Copyright (C) 2019 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.shares.ui.usecases + +import android.accounts.Account +import android.accounts.AccountManager +import android.content.Context +import android.content.Intent +import android.os.Parcelable +import androidx.lifecycle.MutableLiveData +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.hasSibling +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import com.owncloud.android.R +import com.owncloud.android.authentication.AccountAuthenticator.KEY_AUTH_TOKEN_TYPE +import com.owncloud.android.capabilities.db.OCCapability +import com.owncloud.android.capabilities.viewmodel.OCCapabilityViewModel +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.accounts.AccountUtils +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.status.CapabilityBooleanType +import com.owncloud.android.lib.resources.status.OwnCloudVersion +import com.owncloud.android.shares.db.OCShare +import com.owncloud.android.shares.ui.ShareActivity +import com.owncloud.android.shares.viewmodel.OCShareViewModel +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.utils.AccountsManager +import com.owncloud.android.utils.TestUtil +import com.owncloud.android.vo.Resource +import org.hamcrest.Matchers.allOf +import org.hamcrest.Matchers.not +import org.junit.AfterClass +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.mockito.ArgumentMatchers +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import org.mockito.Mockito.spy + +class DeletePublicShareTest { + @Rule + @JvmField + val activityRule = ActivityTestRule( + ShareActivity::class.java, + true, + false + ) + + private lateinit var file: OCFile + + private val publicShares = arrayListOf( + TestUtil.createPublicShare( // With no expiration date + path = "/Photos/image.jpg", + expirationDate = 0L, + isFolder = false, + name = "image.jpg link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "image.jpg updated link", + shareLink = "http://server:port/s/2" + ) + ) + + private val capabilitiesLiveData = MutableLiveData>() + private val sharesLiveData = MutableLiveData>>() + + private val ocCapabilityViewModel = mock(OCCapabilityViewModel::class.java) + private val ocShareViewModel = mock(OCShareViewModel::class.java) + + companion object { + private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext + private val account = Account("admin", "owncloud") + + @BeforeClass + @JvmStatic + fun init() { + addAccount() + } + + @AfterClass + @JvmStatic + fun cleanUp() { + AccountsManager.deleteAllAccounts(targetContext) + } + + private fun addAccount() { + // obtaining an AccountManager instance + val accountManager = AccountManager.get(targetContext) + + accountManager.addAccountExplicitly(account, "a", null) + + // include account version, user, server version and token with the new account + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_VERSION, + OwnCloudVersion("10.2").toString() + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_BASE_URL, + "serverUrl:port" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_DISPLAY_NAME, + "admin" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION, + "1" + ) + + accountManager.setAuthToken( + account, + KEY_AUTH_TOKEN_TYPE, + "AUTH_TOKEN" + ) + } + } + + @Before + fun setUp() { + val intent = spy(Intent::class.java) + + file = getOCFileForTesting("image.jpg") + + `when`(intent.getParcelableExtra(FileActivity.EXTRA_FILE) as? Parcelable).thenReturn(file) + intent.putExtra(FileActivity.EXTRA_FILE, file) + + `when`(ocCapabilityViewModel.getCapabilityForAccount(false)).thenReturn(capabilitiesLiveData) + `when`(ocCapabilityViewModel.getCapabilityForAccount(true)).thenReturn(capabilitiesLiveData) + `when`(ocShareViewModel.getSharesForFile()).thenReturn(sharesLiveData) + + stopKoin() + + startKoin { + androidContext(ApplicationProvider.getApplicationContext()) + modules( + module(override = true) { + viewModel { + ocCapabilityViewModel + } + viewModel { + ocShareViewModel + } + } + ) + } + + activityRule.launchActivity(intent) + } + + @Test + fun deletePublicLink() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares.take(2) as ArrayList + loadSharesSuccessfully(existingPublicShare) + + `when`( + ocShareViewModel.deletePublicShare(ArgumentMatchers.anyLong()) + ).thenReturn( + MutableLiveData>().apply { + postValue(Resource.success()) + } + ) + + onView(allOf(withId(R.id.deletePublicLinkButton), hasSibling(withText(existingPublicShare[0].name)))) + .perform(click()) + onView(withId(android.R.id.button1)).perform(click()) + + sharesLiveData.postValue( + Resource.success( + arrayListOf(existingPublicShare[1]) + ) + ) + + onView(withText(existingPublicShare[0].name)).check(doesNotExist()) + onView(withText(existingPublicShare[1].name)).check(matches(isDisplayed())) + } + + @Test + fun deleteLastPublicLink() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + `when`( + ocShareViewModel.deletePublicShare(ArgumentMatchers.anyLong()) + ).thenReturn( + MutableLiveData>().apply { + postValue(Resource.success()) + } + ) + + onView(withId(R.id.deletePublicLinkButton)).perform(click()) + onView(withId(android.R.id.button1)).perform(click()) + + sharesLiveData.postValue( + Resource.success( + arrayListOf() + ) + ) + + onView(withText(existingPublicShare.name)).check(matches(not(isDisplayed()))) + onView(withText(R.string.share_no_public_links)).check(matches(isDisplayed())) + + } + + @Test + fun deleteShareLoading() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + onView(withId(R.id.deletePublicLinkButton)).perform(click()) + + sharesLiveData.postValue( + Resource.loading( + publicShares + ) + ) + + onView(withText(R.string.common_loading)).check(matches(isDisplayed())) + } + + @Test + fun deleteShareError() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + `when`( + ocShareViewModel.deletePublicShare(ArgumentMatchers.anyLong()) + ).thenReturn( + MutableLiveData>().apply { + postValue( + Resource.error( + RemoteOperationResult.ResultCode.FORBIDDEN, + exception = Exception("Error when retrieving shares") + ) + ) + } + ) + + onView(withId(R.id.deletePublicLinkButton)).perform(click()) + onView(withId(android.R.id.button1)).perform(click()) + + onView(withText(R.string.unshare_link_file_error)).check(matches(isDisplayed())) + } + + private fun getOCFileForTesting(name: String = "default"): OCFile { + val file = OCFile("/Photos/image.jpg") + file.availableOfflineStatus = OCFile.AvailableOfflineStatus.NOT_AVAILABLE_OFFLINE + file.fileName = name + file.fileId = 9456985479 + file.remoteId = "1" + file.privateLink = "image link" + return file + } + + private fun loadCapabilitiesSuccessfully( + capability: OCCapability = TestUtil.createCapability( + versionString = "10.1.1", + sharingPublicMultiple = CapabilityBooleanType.TRUE.value + ) + ) { + capabilitiesLiveData.postValue( + Resource.success( + capability + ) + ) + } + + private fun loadSharesSuccessfully(shares: ArrayList = publicShares) { + sharesLiveData.postValue(Resource.success(shares)) + } +} diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/EditPublicShareFolderTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/EditPublicShareFolderTest.kt new file mode 100644 index 00000000000..a736de01f74 --- /dev/null +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/EditPublicShareFolderTest.kt @@ -0,0 +1,424 @@ +/** + * ownCloud Android client application + * + * @author Jesús Recio (@jesmrec) + * @author David González (@davigonz) + * Copyright (C) 2019 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.shares.ui.usecases + +import android.accounts.Account +import android.accounts.AccountManager +import android.content.Context +import android.content.Intent +import android.os.Parcelable +import androidx.lifecycle.MutableLiveData +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.action.ViewActions.scrollTo +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isChecked +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import com.owncloud.android.R +import com.owncloud.android.authentication.AccountAuthenticator.KEY_AUTH_TOKEN_TYPE +import com.owncloud.android.capabilities.db.OCCapability +import com.owncloud.android.capabilities.viewmodel.OCCapabilityViewModel +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.accounts.AccountUtils +import com.owncloud.android.lib.resources.status.CapabilityBooleanType +import com.owncloud.android.lib.resources.status.OwnCloudVersion +import com.owncloud.android.shares.db.OCShare +import com.owncloud.android.shares.ui.ShareActivity +import com.owncloud.android.shares.viewmodel.OCShareViewModel +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.utils.AccountsManager +import com.owncloud.android.utils.TestUtil +import com.owncloud.android.vo.Resource +import org.junit.AfterClass +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import org.mockito.Mockito.spy + +class EditPublicShareFolderTest { + @Rule + @JvmField + val activityRule = ActivityTestRule( + ShareActivity::class.java, + true, + false + ) + + private lateinit var file: OCFile + + private val publicShares = arrayListOf( + TestUtil.createPublicShare( + path = "/Photos/", + expirationDate = 0L, + permissions = 1, + isFolder = true, + name = "Photos link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( // With name updated + path = "/Photos/", + expirationDate = 0L, + permissions = 1, + isFolder = true, + name = "Photos updated link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( // With permission Download/View/Upload + path = "/Photos/", + expirationDate = 0L, + permissions = 15, + isFolder = true, + name = "Photos link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( // With permission Upload only + path = "/Photos/", + expirationDate = 0L, + permissions = 4, + isFolder = true, + name = "Photos link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( // With password + path = "/Photos/", + expirationDate = 0L, + isFolder = true, + name = "Photos link", + shareLink = "http://server:port/s/1", + shareWith = "1" + ) + ) + + private val capabilitiesLiveData = MutableLiveData>() + private val sharesLiveData = MutableLiveData>>() + + private val ocCapabilityViewModel = mock(OCCapabilityViewModel::class.java) + private val ocShareViewModel = mock(OCShareViewModel::class.java) + + companion object { + private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext + private val account = Account("admin", "owncloud") + + @BeforeClass + @JvmStatic + fun init() { + addAccount() + } + + @AfterClass + @JvmStatic + fun cleanUp() { + AccountsManager.deleteAllAccounts(targetContext) + } + + private fun addAccount() { + // obtaining an AccountManager instance + val accountManager = AccountManager.get(targetContext) + + accountManager.addAccountExplicitly(account, "a", null) + + // include account version, user, server version and token with the new account + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_VERSION, + OwnCloudVersion("10.2").toString() + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_BASE_URL, + "serverUrl:port" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_DISPLAY_NAME, + "admin" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION, + "1" + ) + + accountManager.setAuthToken( + account, + KEY_AUTH_TOKEN_TYPE, + "AUTH_TOKEN" + ) + } + } + + @Before + fun setUp() { + val intent = spy(Intent::class.java) + + file = getOCFileForTesting("Photos") + + `when`(intent.getParcelableExtra(FileActivity.EXTRA_FILE) as? Parcelable).thenReturn(file) + intent.putExtra(FileActivity.EXTRA_FILE, file) + + `when`(ocCapabilityViewModel.getCapabilityForAccount(false)).thenReturn(capabilitiesLiveData) + `when`(ocCapabilityViewModel.getCapabilityForAccount(true)).thenReturn(capabilitiesLiveData) + `when`(ocShareViewModel.getSharesForFile()).thenReturn(sharesLiveData) + + stopKoin() + + startKoin { + androidContext(ApplicationProvider.getApplicationContext()) + modules( + module(override = true) { + viewModel { + ocCapabilityViewModel + } + viewModel { + ocShareViewModel + } + } + ) + } + + activityRule.launchActivity(intent) + } + + @Test + fun editNameFolder() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + val updatedPublicShare = publicShares[1] + + `when`( + ocShareViewModel.updatePublicShareForFile( + 1, + updatedPublicShare.name!!, + "", + -1, + 1, + false + ) + ).thenReturn( + MutableLiveData>().apply { + postValue(Resource.success()) + } + ) + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Update fields + onView(withId(R.id.shareViaLinkNameValue)).perform(replaceText(updatedPublicShare.name)) + + // 3. Save updated share + onView(withId(R.id.saveButton)).perform(scrollTo(), click()) + + // 4. Share properly updated + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // Check whether the dialog to create the public share has been properly closed + onView(withText(R.string.share_via_link_edit_title)).check(doesNotExist()) + onView(withText(updatedPublicShare.name)).check(matches(isDisplayed())) + } + + @Test + fun editPermissionToDownloadViewUpload() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + val updatedPublicShare = publicShares[2] + `when`( + ocShareViewModel.updatePublicShareForFile( + 1, + updatedPublicShare.name!!, + "", + -1, + 15, + true + ) + ).thenReturn( + MutableLiveData>().apply { + postValue(Resource.success()) + } + ) + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Update fields + onView(withId(R.id.shareViaLinkEditPermissionReadAndWrite)).perform(click()) + + // 3. Save updated share + onView(withId(R.id.saveButton)).perform(scrollTo(), click()) + + // 4. Share properly updated + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // Open Dialog to check correct permission change + onView(withId(R.id.editPublicLinkButton)).perform(click()) + onView(withId(R.id.shareViaLinkEditPermissionReadAndWrite)).check(matches(isChecked())) + + } + + @Test + fun editPermissionToUploadOnly() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + val updatedPublicShare = publicShares[3] + `when`( + ocShareViewModel.updatePublicShareForFile( + 1, + updatedPublicShare.name!!, + "", + -1, + 4, + true + ) + ).thenReturn( + MutableLiveData>().apply { + postValue(Resource.success()) + } + ) + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Update fields + onView(withId(R.id.shareViaLinkEditPermissionUploadFiles)).perform(click()) + + // 3. Save updated share + onView(withId(R.id.saveButton)).perform(scrollTo(), click()) + + // 4. Share properly updated + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // Open Dialog to check correct permission change + onView(withId(R.id.editPublicLinkButton)).perform(click()) + onView(withId(R.id.shareViaLinkEditPermissionUploadFiles)).check(matches(isChecked())) + + } + + @Test + fun editPermissionToDownloadView() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[2] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + val updatedPublicShare = publicShares[0] + `when`( + ocShareViewModel.updatePublicShareForFile( + 1, + updatedPublicShare.name!!, + "", + -1, + 1, + false + ) + ).thenReturn( + MutableLiveData>().apply { + postValue(Resource.success()) + } + ) + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Update fields + onView(withId(R.id.shareViaLinkEditPermissionReadOnly)).perform(click()) + + // 3. Save updated share + onView(withId(R.id.saveButton)).perform(scrollTo(), click()) + + // 4. Share properly updated + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // Open Dialog to check correct permission change + onView(withId(R.id.editPublicLinkButton)).perform(click()) + onView(withId(R.id.shareViaLinkEditPermissionReadOnly)).check(matches(isChecked())) + + } + + private fun getOCFileForTesting(name: String = "default"): OCFile { + val file = OCFile("/Photos") + file.availableOfflineStatus = OCFile.AvailableOfflineStatus.NOT_AVAILABLE_OFFLINE + file.fileName = name + file.fileId = 9456985479 + file.remoteId = "1" + file.mimetype = "DIR" + file.privateLink = "private link" + return file + } + + private fun loadCapabilitiesSuccessfully( + capability: OCCapability = TestUtil.createCapability( + versionString = "10.1.1", + sharingPublicMultiple = CapabilityBooleanType.TRUE.value, + sharingPublicSupportsUploadOnly = CapabilityBooleanType.TRUE.value, + sharingPublicUpload = CapabilityBooleanType.TRUE.value + ) + ) { + capabilitiesLiveData.postValue( + Resource.success( + capability + ) + ) + } + + private fun loadSharesSuccessfully(shares: ArrayList = publicShares) { + sharesLiveData.postValue(Resource.success(shares)) + } +} diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/EditPublicShareTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/EditPublicShareTest.kt new file mode 100644 index 00000000000..d14f9b8ba36 --- /dev/null +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/EditPublicShareTest.kt @@ -0,0 +1,467 @@ +/** + * ownCloud Android client application + * + * @author David González Verdugo + * Copyright (C) 2019 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.shares.ui.usecases + +import android.accounts.Account +import android.accounts.AccountManager +import android.content.Context +import android.content.Intent +import android.os.Parcelable +import android.widget.DatePicker +import androidx.lifecycle.MutableLiveData +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.replaceText +import androidx.test.espresso.action.ViewActions.typeText +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.contrib.PickerActions +import androidx.test.espresso.matcher.ViewMatchers.isChecked +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.isNotChecked +import androidx.test.espresso.matcher.ViewMatchers.withClassName +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import com.owncloud.android.R +import com.owncloud.android.authentication.AccountAuthenticator.KEY_AUTH_TOKEN_TYPE +import com.owncloud.android.capabilities.db.OCCapability +import com.owncloud.android.capabilities.viewmodel.OCCapabilityViewModel +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.accounts.AccountUtils +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.status.CapabilityBooleanType +import com.owncloud.android.lib.resources.status.OwnCloudVersion +import com.owncloud.android.shares.db.OCShare +import com.owncloud.android.shares.ui.ShareActivity +import com.owncloud.android.shares.viewmodel.OCShareViewModel +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.utils.AccountsManager +import com.owncloud.android.utils.TestUtil +import com.owncloud.android.vo.Resource +import org.hamcrest.Matchers +import org.junit.AfterClass +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import org.mockito.Mockito.spy +import java.text.DateFormat +import java.text.SimpleDateFormat +import java.util.Calendar + +class EditPublicShareTest { + @Rule + @JvmField + val activityRule = ActivityTestRule( + ShareActivity::class.java, + true, + false + ) + + private lateinit var file: OCFile + + private val publicShares = arrayListOf( + TestUtil.createPublicShare( // With no expiration date + path = "/Photos/image.jpg", + expirationDate = 0L, + isFolder = false, + name = "image.jpg link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "image.jpg updated link", + shareLink = "http://server:port/s/2" + ), + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "image.jpg changed again link", + shareLink = "http://server:port/s/3" + ), + TestUtil.createPublicShare( // With password but not expiration date + path = "/Photos/image.jpg", + expirationDate = 0L, + isFolder = false, + name = "image.jpg link", + shareLink = "http://server:port/s/1", + shareWith = "1" + ), + TestUtil.createPublicShare( // With expiration date but not password + path = "/Photos/image.jpg", + expirationDate = 2587896257, + isFolder = false, + name = "image.jpg link", + shareLink = "http://server:port/s/1" + ) + ) + + private val capabilitiesLiveData = MutableLiveData>() + private val sharesLiveData = MutableLiveData>>() + + private val ocCapabilityViewModel = mock(OCCapabilityViewModel::class.java) + private val ocShareViewModel = mock(OCShareViewModel::class.java) + + companion object { + private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext + private val account = Account("admin", "owncloud") + + @BeforeClass + @JvmStatic + fun init() { + addAccount() + } + + @AfterClass + @JvmStatic + fun cleanUp() { + AccountsManager.deleteAllAccounts(targetContext) + } + + private fun addAccount() { + // obtaining an AccountManager instance + val accountManager = AccountManager.get(targetContext) + + accountManager.addAccountExplicitly(account, "a", null) + + // include account version, user, server version and token with the new account + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_VERSION, + OwnCloudVersion("10.2").toString() + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_BASE_URL, + "serverUrl:port" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_DISPLAY_NAME, + "admin" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION, + "1" + ) + + accountManager.setAuthToken( + account, + KEY_AUTH_TOKEN_TYPE, + "AUTH_TOKEN" + ) + } + } + + @Before + fun setUp() { + val intent = spy(Intent::class.java) + + file = getOCFileForTesting("image.jpg") + + `when`(intent.getParcelableExtra(FileActivity.EXTRA_FILE) as? Parcelable).thenReturn(file) + intent.putExtra(FileActivity.EXTRA_FILE, file) + + `when`(ocCapabilityViewModel.getCapabilityForAccount(false)).thenReturn(capabilitiesLiveData) + `when`(ocCapabilityViewModel.getCapabilityForAccount(true)).thenReturn(capabilitiesLiveData) + `when`(ocShareViewModel.getSharesForFile()).thenReturn(sharesLiveData) + + stopKoin() + + startKoin { + androidContext(ApplicationProvider.getApplicationContext()) + modules( + module(override = true) { + viewModel { + ocCapabilityViewModel + } + viewModel { + ocShareViewModel + } + } + ) + } + + activityRule.launchActivity(intent) + } + + @Test + fun editName() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + val updatedPublicShare = publicShares[1] + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Update fields + onView(withId(R.id.shareViaLinkNameValue)).perform(replaceText(updatedPublicShare.name)) + + // 3. Edit public share with success + editPublicShare(updatedPublicShare, "", resource = Resource.success()) + + // 4. Share properly updated + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // 5. Check whether the dialog to create the public share has been properly closed + onView(withText(R.string.share_via_link_edit_title)).check(doesNotExist()) + onView(withText(updatedPublicShare.name)).check(matches(isDisplayed())) + } + + @Test + fun addPassword() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + val password = "1234" + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Enable password and type it + onView(withId(R.id.shareViaLinkPasswordSwitch)).perform(click()) + onView(withId(R.id.shareViaLinkPasswordValue)).perform(typeText(password)) + + // 3. Edit public share with success + editPublicShare(existingPublicShare, "1234", resource = Resource.success()) + + // 4. Share properly updated + val updatedPublicShare = publicShares[3] + + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // 5. Open dialog to check whether the password has been properly set + onView(withId(R.id.editPublicLinkButton)).perform(click()) + onView(withId(R.id.shareViaLinkPasswordSwitch)).check(matches(isChecked())) + } + + @Test + fun removePassword() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[3] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Disable password + onView(withId(R.id.shareViaLinkPasswordSwitch)).perform(click()) + + // 3. Edit public share with success + editPublicShare(existingPublicShare, "", resource = Resource.success()) + + // 4. Share properly updated + val updatedPublicShare = publicShares[0] + + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // 5. Open dialog to check whether the password has been properly disabled + onView(withId(R.id.editPublicLinkButton)).perform(click()) + onView(withId(R.id.shareViaLinkPasswordSwitch)).check(matches(isNotChecked())) + } + + @Test + fun addExpirationDate() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + val calendar = Calendar.getInstance() + calendar.add(Calendar.DAY_OF_YEAR, 1) + val formatter: DateFormat = SimpleDateFormat("MMM dd, yyyy"); + val expirationDate = formatter.format(calendar.time); + val publicLinkExpirationDateInMillis = SimpleDateFormat.getDateInstance().parse(expirationDate).time + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Enable expiration date and set it + onView(withId(R.id.shareViaLinkExpirationSwitch)).perform(click()) + onView(withClassName(Matchers.equalTo(DatePicker::class.java.name))).perform( + PickerActions.setDate( + calendar.get(Calendar.YEAR), + calendar.get(Calendar.MONTH) + 1, // January code is 0, so let's add 1 + calendar.get(Calendar.DATE) + ) + ); + onView(withId(android.R.id.button1)).perform(click()) + + // 3. Edit public share with success + editPublicShare(existingPublicShare, "", publicLinkExpirationDateInMillis, Resource.success()) + + // 4. Share properly updated + val updatedPublicShare = publicShares[4] + + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // 5. Open dialog to check whether the expiration date is enabled + onView(withId(R.id.editPublicLinkButton)).perform(click()) + onView(withId(R.id.shareViaLinkExpirationSwitch)).check(matches(isChecked())) + } + + @Test + fun removeExpirationDate() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[4] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + // 1. Open dialog to edit an existing public share + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + // 2. Disable expiration date + onView(withId(R.id.shareViaLinkExpirationSwitch)).perform(click()) + + // 3. Edit public share with success + editPublicShare(existingPublicShare, "", resource = Resource.success()) + + // 4. Share properly updated + val updatedPublicShare = publicShares[0] + + sharesLiveData.postValue( + Resource.success( + arrayListOf(updatedPublicShare) + ) + ) + + // 5. Open dialog to check whether the expiration date is disabled + onView(withId(R.id.editPublicLinkButton)).perform(click()) + onView(withId(R.id.shareViaLinkExpirationSwitch)).check(matches(isNotChecked())) + } + + @Test + fun editShareLoading() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[3] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + editPublicShare(existingPublicShare, resource = Resource.loading()) + + onView(withText(R.string.common_loading)).check(matches(isDisplayed())) + } + + @Test + fun editShareError() { + loadCapabilitiesSuccessfully() + + val existingPublicShare = publicShares[0] + loadSharesSuccessfully(arrayListOf(existingPublicShare)) + + onView(withId(R.id.editPublicLinkButton)).perform(click()) + + editPublicShare( + existingPublicShare, + password = "", + resource = Resource.error( + RemoteOperationResult.ResultCode.FORBIDDEN, + exception = Exception("Error when retrieving shares") + ) + ) + + onView(withText(R.string.update_link_file_error)).check(matches(isDisplayed())) + } + + private fun getOCFileForTesting(name: String = "default") = OCFile("/Photos").apply { + availableOfflineStatus = OCFile.AvailableOfflineStatus.NOT_AVAILABLE_OFFLINE + fileName = name + fileId = 9456985479 + remoteId = "1" + privateLink = "private link" + } + + private fun loadCapabilitiesSuccessfully( + capability: OCCapability = TestUtil.createCapability( + versionString = "10.1.1", + sharingPublicMultiple = CapabilityBooleanType.TRUE.value + ) + ) { + capabilitiesLiveData.postValue( + Resource.success( + capability + ) + ) + } + + private fun loadSharesSuccessfully(shares: ArrayList = publicShares) { + sharesLiveData.postValue(Resource.success(shares)) + } + + private fun editPublicShare( + share: OCShare, + password: String? = null, + publicLinkExpirationDateInMillis: Long = -1, + resource: Resource = Resource.success() // Expected result when editing the share + ) { + `when`( + ocShareViewModel.updatePublicShareForFile( + 1, + share.name!!, + password, + publicLinkExpirationDateInMillis, + 1, + false + ) + ).thenReturn( + MutableLiveData>().apply { + postValue(resource) + } + ) + + onView(withId(R.id.saveButton)).perform(click()) + } +} diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/LoadPublicSharesTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/LoadPublicSharesTest.kt new file mode 100644 index 00000000000..4aad14dc63e --- /dev/null +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/ui/usecases/LoadPublicSharesTest.kt @@ -0,0 +1,236 @@ +/** + * ownCloud Android client application + * + * @author David González Verdugo + * Copyright (C) 2019 ownCloud GmbH. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.owncloud.android.shares.ui.usecases + +import android.accounts.Account +import android.accounts.AccountManager +import android.content.Context +import android.content.Intent +import android.os.Parcelable +import androidx.lifecycle.MutableLiveData +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.matcher.ViewMatchers.withText +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.ActivityTestRule +import com.owncloud.android.R +import com.owncloud.android.authentication.AccountAuthenticator.KEY_AUTH_TOKEN_TYPE +import com.owncloud.android.capabilities.db.OCCapability +import com.owncloud.android.capabilities.viewmodel.OCCapabilityViewModel +import com.owncloud.android.datamodel.OCFile +import com.owncloud.android.lib.common.accounts.AccountUtils +import com.owncloud.android.lib.common.operations.RemoteOperationResult +import com.owncloud.android.lib.resources.status.OwnCloudVersion +import com.owncloud.android.shares.db.OCShare +import com.owncloud.android.shares.ui.ShareActivity +import com.owncloud.android.shares.viewmodel.OCShareViewModel +import com.owncloud.android.ui.activity.FileActivity +import com.owncloud.android.utils.AccountsManager +import com.owncloud.android.utils.TestUtil +import com.owncloud.android.vo.Resource +import org.junit.AfterClass +import org.junit.Before +import org.junit.BeforeClass +import org.junit.Rule +import org.junit.Test +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.mockito.Mockito.`when` +import org.mockito.Mockito.mock +import org.mockito.Mockito.spy + +class LoadPublicSharesTest { + @Rule + @JvmField + val activityRule = ActivityTestRule( + ShareActivity::class.java, + true, + false + ) + + private val publicShares = arrayListOf( + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "Image link", + shareLink = "http://server:port/s/1" + ), + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "Image link 2", + shareLink = "http://server:port/s/2" + ), + TestUtil.createPublicShare( + path = "/Photos/image.jpg", + isFolder = false, + name = "Image link 3", + shareLink = "http://server:port/s/3" + ) + ) + + private val capabilitiesLiveData = MutableLiveData>() + private val sharesLiveData = MutableLiveData>>() + + private val ocCapabilityViewModel = mock(OCCapabilityViewModel::class.java) + private val ocShareViewModel = mock(OCShareViewModel::class.java) + + companion object { + private val targetContext = InstrumentationRegistry.getInstrumentation().targetContext + private val account = Account("admin", "owncloud") + + @BeforeClass + @JvmStatic + fun init() { + addAccount() + } + + @AfterClass + @JvmStatic + fun cleanUp() { + AccountsManager.deleteAllAccounts(targetContext) + } + + private fun addAccount() { + // obtaining an AccountManager instance + val accountManager = AccountManager.get(targetContext) + + accountManager.addAccountExplicitly(account, "a", null) + + // include account version, user, server version and token with the new account + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_VERSION, + OwnCloudVersion("10.2").toString() + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_BASE_URL, + "serverUrl:port" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_DISPLAY_NAME, + "admin" + ) + accountManager.setUserData( + account, + AccountUtils.Constants.KEY_OC_ACCOUNT_VERSION, + "1" + ) + + accountManager.setAuthToken( + account, + KEY_AUTH_TOKEN_TYPE, + "AUTH_TOKEN" + ) + } + } + + @Before + fun setUp() { + val intent = spy(Intent::class.java) + + val file = getOCFileForTesting("image.jpg") + + `when`(intent.getParcelableExtra(FileActivity.EXTRA_FILE) as? Parcelable).thenReturn(file) + intent.putExtra(FileActivity.EXTRA_FILE, file) + + `when`(ocCapabilityViewModel.getCapabilityForAccount()).thenReturn(capabilitiesLiveData) + `when`(ocShareViewModel.getSharesForFile()).thenReturn(sharesLiveData) + + stopKoin() + + startKoin { + androidContext(ApplicationProvider.getApplicationContext()) + modules( + module(override = true) { + viewModel { + ocCapabilityViewModel + } + viewModel { + ocShareViewModel + } + } + ) + } + + activityRule.launchActivity(intent) + } + + @Test + fun showLoadingCapabilitiesDialog() { + capabilitiesLiveData.postValue(Resource.loading(TestUtil.createCapability())) + onView(withId(R.id.loadingLayout)).check(matches(isDisplayed())) + } + + @Test + fun showLoadingSharesDialog() { + loadCapabilitiesSuccessfully() + sharesLiveData.postValue(Resource.loading(publicShares)) + onView(withId(R.id.loadingLayout)).check(matches(isDisplayed())) + } + + @Test + fun showErrorWhenLoadingCapabilities() { + capabilitiesLiveData.postValue( + Resource.error( + RemoteOperationResult.ResultCode.SERVICE_UNAVAILABLE + ) + ) + + onView(withId(R.id.snackbar_text)).check(matches(withText(R.string.service_unavailable))) + } + + @Test + fun showErrorWhenLoadingShares() { + loadCapabilitiesSuccessfully() + + sharesLiveData.postValue( + Resource.error( + RemoteOperationResult.ResultCode.SERVICE_UNAVAILABLE, + data = publicShares + ) + ) + onView(withId(R.id.snackbar_text)).check(matches(withText(R.string.service_unavailable))) + } + + private fun getOCFileForTesting(name: String = "default") = OCFile("/Photos").apply { + availableOfflineStatus = OCFile.AvailableOfflineStatus.NOT_AVAILABLE_OFFLINE + fileName = name + fileId = 9456985479 + remoteId = "1" + privateLink = "private link" + } + + private fun loadCapabilitiesSuccessfully(capability: OCCapability = TestUtil.createCapability()) { + capabilitiesLiveData.postValue( + Resource.success( + capability + ) + ) + } +} diff --git a/owncloudApp/src/test/java/com/owncloud/android/shares/viewmodel/OCShareViewModelTest.kt b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/viewmodel/OCShareViewModelTest.kt similarity index 79% rename from owncloudApp/src/test/java/com/owncloud/android/shares/viewmodel/OCShareViewModelTest.kt rename to owncloudApp/src/androidTest/java/com/owncloud/android/shares/viewmodel/OCShareViewModelTest.kt index 68aff91b32c..63d53ad6841 100644 --- a/owncloudApp/src/test/java/com/owncloud/android/shares/viewmodel/OCShareViewModelTest.kt +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/shares/viewmodel/OCShareViewModelTest.kt @@ -22,13 +22,14 @@ package com.owncloud.android.shares.viewmodel import android.accounts.Account import androidx.arch.core.executor.testing.InstantTaskExecutorRule import androidx.lifecycle.MutableLiveData +import androidx.test.platform.app.InstrumentationRegistry import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.shares.db.OCShare import com.owncloud.android.shares.repository.OCShareRepository import com.owncloud.android.utils.TestUtil import com.owncloud.android.vo.Resource +import com.owncloud.android.vo.Status import junit.framework.Assert.assertEquals -import org.junit.Before import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -43,11 +44,10 @@ class OCShareViewModelTest { val instantExecutorRule = InstantTaskExecutorRule() private var testAccount: Account = TestUtil.createAccount("admin@server", "test") - private val publicShareResourcesAsLiveData: MutableLiveData>> = MutableLiveData() private var ocShareRepository: OCShareRepository = mock(OCShareRepository::class.java) - @Before - fun init() { + @Test + fun loadPublicShares() { val publicShares = mutableListOf( TestUtil.createPublicShare( path = "/Photos/image.jpg", @@ -63,19 +63,12 @@ class OCShareViewModelTest { ) ) - publicShareResourcesAsLiveData.value = Resource.success(publicShares) - } - - @Test - fun loadPublicShares() { `when`( - ocShareRepository.loadSharesForFile( - listOf(ShareType.PUBLIC_LINK), - reshares = true, - subfiles = false - ) + ocShareRepository.getSharesForFile() ).thenReturn( - publicShareResourcesAsLiveData + MutableLiveData>>().apply { + value = Resource.success(publicShares) + } ) // Viewmodel that will ask ocShareRepository for shares @@ -98,13 +91,15 @@ class OCShareViewModelTest { false ) ).thenReturn( - publicShareResourcesAsLiveData + MutableLiveData>().apply { + value = Resource.success() + } ) // Viewmodel that will ask ocShareRepository for shares val ocShareViewModel = createOCShareViewModel(ocShareRepository) - val resource: Resource>? = ocShareViewModel.insertPublicShareForFile( + val resource: Resource? = ocShareViewModel.insertPublicShareForFile( 1, "Photos 2 link", "1234", @@ -112,7 +107,7 @@ class OCShareViewModelTest { false ).value - assertShareParameters(resource?.data) + assertEquals(Status.SUCCESS, resource?.status) } @Test @@ -122,29 +117,31 @@ class OCShareViewModelTest { `when`( ocShareRepository.updatePublicShareForFile( 1, - "Photos 2 link", - "1234", + "Photos 1 link", + "123456", 1000, 1, false ) ).thenReturn( - publicShareResourcesAsLiveData + MutableLiveData>().apply { + value = Resource.success() + } ) // Viewmodel that will ask ocShareRepository for shares val ocShareViewModel = createOCShareViewModel(ocShareRepository) - val resource: Resource>? = ocShareViewModel.updatePublicShareForFile( + val resource: Resource? = ocShareViewModel.updatePublicShareForFile( 1, - "Photos 2 link", - "1234", + "Photos 1 link", + "123456", 1000, 1, false ).value - assertShareParameters(resource?.data) + assertEquals(Status.SUCCESS, resource?.status) } @Test @@ -156,26 +153,32 @@ class OCShareViewModelTest { 3 ) ).thenReturn( - publicShareResourcesAsLiveData + MutableLiveData>().apply { + value = Resource.success() + } ) // Viewmodel that will ask ocShareRepository for shares val ocShareViewModel = createOCShareViewModel(ocShareRepository) - val resource: Resource>? = ocShareViewModel.deletePublicShare( + val resource: Resource? = ocShareViewModel.deletePublicShare( 3 ).value - assertShareParameters(resource?.data) + assertEquals(Status.SUCCESS, resource?.status) } - private fun createOCShareViewModel(ocShareRepository: OCShareRepository): OCShareViewModel = - OCShareViewModel( + private fun createOCShareViewModel(ocShareRepository: OCShareRepository): OCShareViewModel { + val context = InstrumentationRegistry.getInstrumentation().targetContext + + return OCShareViewModel( + context, "/Photos/image.jpg", testAccount, listOf(ShareType.PUBLIC_LINK), ocShareRepository ) + } private fun assertShareParameters(shares: List?) { assertEquals(2, shares?.size) diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/ui/activity/PublicShareActivityTest.java b/owncloudApp/src/androidTest/java/com/owncloud/android/ui/activity/PublicShareActivityTest.java index 7dc8210ae70..7f52440d198 100644 --- a/owncloudApp/src/androidTest/java/com/owncloud/android/ui/activity/PublicShareActivityTest.java +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/ui/activity/PublicShareActivityTest.java @@ -134,7 +134,6 @@ public void beforeActivityLaunched() { @Before public void init() { - // UiDevice available from API level 17 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { diff --git a/owncloudApp/src/androidTest/java/com/owncloud/android/utils/AccountsManager.java b/owncloudApp/src/androidTest/java/com/owncloud/android/utils/AccountsManager.java index 520babedfd3..dbd0db68826 100644 --- a/owncloudApp/src/androidTest/java/com/owncloud/android/utils/AccountsManager.java +++ b/owncloudApp/src/androidTest/java/com/owncloud/android/utils/AccountsManager.java @@ -116,7 +116,7 @@ public static RemoteCapability getCapabilities(String server, String user, Strin public static void saveCapabilities(Context context, RemoteCapability capabilities, String server, String user) { FileDataStorageManager fm = new FileDataStorageManager(context, new Account(buildAccountName(user, server), accountType), - MainApp.getAppContext().getContentResolver()); + MainApp.Companion.getAppContext().getContentResolver()); fm.saveCapabilities(capabilities); } diff --git a/owncloudApp/src/main/java/com/owncloud/android/MainApp.java b/owncloudApp/src/main/java/com/owncloud/android/MainApp.java deleted file mode 100644 index e95af64c763..00000000000 --- a/owncloudApp/src/main/java/com/owncloud/android/MainApp.java +++ /dev/null @@ -1,268 +0,0 @@ -/** - * ownCloud Android client application - * - * @author masensio - * @author David A. Velasco - * @author David González Verdugo - * @author Christian Schabesberger - * Copyright (C) 2019 ownCloud GmbH. - *

- * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. - *

- * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - *

- * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.owncloud.android; - -import android.app.Activity; -import android.app.Application; -import android.content.Context; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; - -import com.owncloud.android.authentication.FingerprintManager; -import com.owncloud.android.authentication.PassCodeManager; -import com.owncloud.android.authentication.PatternManager; -import com.owncloud.android.datamodel.ThumbnailsCacheManager; -import com.owncloud.android.lib.common.OwnCloudClient; -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; -import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy; -import com.owncloud.android.lib.common.authentication.oauth.OAuth2ClientConfiguration; -import com.owncloud.android.lib.common.authentication.oauth.OAuth2ProvidersRegistry; -import com.owncloud.android.lib.common.authentication.oauth.OwnCloudOAuth2Provider; -import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.ui.activity.FingerprintActivity; -import com.owncloud.android.ui.activity.PassCodeActivity; -import com.owncloud.android.ui.activity.PatternLockActivity; -import com.owncloud.android.ui.activity.WhatsNewActivity; - -/** - * Main Application of the project - * - * Contains methods to build the "static" strings. These strings were before constants in different - * classes - */ -public class MainApp extends Application { - - private static final String TAG = MainApp.class.getSimpleName(); - - private static final String AUTH_ON = "on"; - - @SuppressWarnings("unused") - private static final String POLICY_SINGLE_SESSION_PER_ACCOUNT = "single session per account"; - @SuppressWarnings("unused") - private static final String POLICY_ALWAYS_NEW_CLIENT = "always new client"; - - private static Context mContext; - - public static String BETA_VERSION = "beta"; - - public void onCreate() { - super.onCreate(); - MainApp.mContext = getApplicationContext(); - - OwnCloudClient.setContext(mContext); - - boolean isSamlAuth = AUTH_ON.equals(getString(R.string.auth_method_saml_web_sso)); - - OwnCloudClientManagerFactory.setUserAgent(getUserAgent()); - if (isSamlAuth) { - OwnCloudClientManagerFactory.setDefaultPolicy(Policy.SINGLE_SESSION_PER_ACCOUNT); - } else { - OwnCloudClientManagerFactory.setDefaultPolicy( - Policy.SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING - ); - } - - OwnCloudOAuth2Provider oauth2Provider = new OwnCloudOAuth2Provider(); - oauth2Provider.setAuthorizationCodeEndpointPath( - getString(R.string.oauth2_url_endpoint_auth) - ); - oauth2Provider.setAccessTokenEndpointPath( - getString(R.string.oauth2_url_endpoint_access) - ); - oauth2Provider.setClientConfiguration( - new OAuth2ClientConfiguration( - getString(R.string.oauth2_client_id), - getString(R.string.oauth2_client_secret), - getString(R.string.oauth2_redirect_uri) - ) - ); - - OAuth2ProvidersRegistry.getInstance().registerProvider( - OwnCloudOAuth2Provider.NAME, - oauth2Provider - ); - - // initialise thumbnails cache on background thread - new ThumbnailsCacheManager.InitDiskCacheTask().execute(); - - if (BuildConfig.DEBUG || isBeta()) { - - String dataFolder = getDataFolder(); - - // Set folder for store logs - Log_OC.setLogDataFolder(dataFolder); - - Log_OC.startLogging(Environment.getExternalStorageDirectory().getAbsolutePath()); - Log_OC.d(BuildConfig.BUILD_TYPE, "start logging " + BuildConfig.VERSION_NAME); - } - - // register global protection with pass code, pattern lock and fingerprint lock - registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { - - @Override - public void onActivityCreated(Activity activity, Bundle savedInstanceState) { - Log_OC.d(activity.getClass().getSimpleName(), "onCreate(Bundle) starting"); - PassCodeManager.getPassCodeManager().onActivityCreated(activity); - PatternManager.getPatternManager().onActivityCreated(activity); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - FingerprintManager.getFingerprintManager(activity).onActivityCreated(activity); - } - // If there's any lock protection, don't show wizard at this point, show it when lock activities - // have finished - if (!(activity instanceof PassCodeActivity) && - !(activity instanceof PatternLockActivity) && - !(activity instanceof FingerprintActivity)) { - WhatsNewActivity.runIfNeeded(activity); - } - } - - @Override - public void onActivityStarted(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onStart() starting"); - PassCodeManager.getPassCodeManager().onActivityStarted(activity); - PatternManager.getPatternManager().onActivityStarted(activity); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - FingerprintManager.getFingerprintManager(activity).onActivityStarted(activity); - } - } - - @Override - public void onActivityResumed(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onResume() starting"); - } - - @Override - public void onActivityPaused(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onPause() ending"); - } - - @Override - public void onActivityStopped(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onStop() ending"); - PassCodeManager.getPassCodeManager().onActivityStopped(activity); - PatternManager.getPatternManager().onActivityStopped(activity); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - FingerprintManager.getFingerprintManager(activity).onActivityStopped(activity); - } - if (activity instanceof PassCodeActivity || - activity instanceof PatternLockActivity || - activity instanceof FingerprintActivity) { - WhatsNewActivity.runIfNeeded(activity); - } - } - - @Override - public void onActivitySaveInstanceState(Activity activity, Bundle outState) { - Log_OC.d(activity.getClass().getSimpleName(), "onSaveInstanceState(Bundle) starting"); - } - - @Override - public void onActivityDestroyed(Activity activity) { - Log_OC.d(activity.getClass().getSimpleName(), "onDestroy() ending"); - } - }); - } - - public static Context getAppContext() { - return MainApp.mContext; - } - - /** - * Next methods give access in code to some constants that need to be defined in string resources to be referred - * in AndroidManifest.xml file or other xml resource files; or that need to be easy to modify in build time. - */ - - public static String getAccountType() { - return getAppContext().getResources().getString(R.string.account_type); - } - - public static int getVersionCode() { - try { - String thisPackageName = getAppContext().getPackageName(); - return getAppContext().getPackageManager().getPackageInfo(thisPackageName, 0).versionCode; - } catch (PackageManager.NameNotFoundException e) { - return 0; - } - } - - public static String getAuthority() { - return getAppContext().getResources().getString(R.string.authority); - } - - public static String getAuthTokenType() { - return getAppContext().getResources().getString(R.string.authority); - } - - public static String getDBFile() { - return getAppContext().getResources().getString(R.string.db_file); - } - - public static String getDBName() { - return getAppContext().getResources().getString(R.string.db_name); - } - - public static String getDataFolder() { - return getAppContext().getResources().getString(R.string.data_folder); - } - - public static String getLogName() { - return getAppContext().getResources().getString(R.string.log_name); - } - - // user agent - public static String getUserAgent() { - String appString = getAppContext().getResources().getString(R.string.user_agent); - String packageName = getAppContext().getPackageName(); - String version = ""; - - PackageInfo pInfo; - try { - pInfo = getAppContext().getPackageManager().getPackageInfo(packageName, 0); - if (pInfo != null) { - version = pInfo.versionName; - } - } catch (PackageManager.NameNotFoundException e) { - Log_OC.e(TAG, "Trying to get packageName", e.getCause()); - } - - // Mozilla/5.0 (Android) ownCloud-android/1.7.0 - return String.format(appString, version); - } - - public static boolean isBeta() { - boolean isBeta = false; - try { - String packageName = getAppContext().getPackageName(); - PackageInfo packageInfo = getAppContext().getPackageManager().getPackageInfo(packageName, 0); - String versionName = packageInfo.versionName; - if (versionName.contains(BETA_VERSION)) { - isBeta = true; - } - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - return isBeta; - } -} diff --git a/owncloudApp/src/main/java/com/owncloud/android/MainApp.kt b/owncloudApp/src/main/java/com/owncloud/android/MainApp.kt new file mode 100644 index 00000000000..b7b3b1faf6e --- /dev/null +++ b/owncloudApp/src/main/java/com/owncloud/android/MainApp.kt @@ -0,0 +1,275 @@ +/** + * ownCloud Android client application + * + * @author masensio + * @author David A. Velasco + * @author David González Verdugo + * @author Christian Schabesberger + * Copyright (C) 2019 ownCloud GmbH. + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see //www.gnu.org/licenses/>. + */ +package com.owncloud.android + +import android.accounts.Account +import android.app.Activity +import android.app.Application +import android.content.Context +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.os.Build +import android.os.Bundle +import android.os.Environment + +import com.owncloud.android.authentication.FingerprintManager +import com.owncloud.android.authentication.PassCodeManager +import com.owncloud.android.authentication.PatternManager +import com.owncloud.android.capabilities.viewmodel.OCCapabilityViewModel +import com.owncloud.android.datamodel.ThumbnailsCacheManager +import com.owncloud.android.lib.common.OwnCloudClient +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory.Policy +import com.owncloud.android.lib.common.authentication.oauth.OAuth2ClientConfiguration +import com.owncloud.android.lib.common.authentication.oauth.OAuth2ProvidersRegistry +import com.owncloud.android.lib.common.authentication.oauth.OwnCloudOAuth2Provider +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.lib.resources.shares.ShareType +import com.owncloud.android.shares.viewmodel.OCShareViewModel +import com.owncloud.android.ui.activity.FingerprintActivity +import com.owncloud.android.ui.activity.PassCodeActivity +import com.owncloud.android.ui.activity.PatternLockActivity +import com.owncloud.android.ui.activity.WhatsNewActivity +import org.koin.android.ext.koin.androidContext +import org.koin.androidx.viewmodel.dsl.viewModel +import org.koin.core.context.startKoin +import org.koin.dsl.module + +/** + * Main Application of the project + * + * Contains methods to build the "static" strings. These strings were before constants in different + * classes + */ +class MainApp : Application() { + + override fun onCreate() { + super.onCreate() + + appContext = applicationContext + + OwnCloudClient.setContext(appContext) + + val isSamlAuth = AUTH_ON == getString(R.string.auth_method_saml_web_sso) + + OwnCloudClientManagerFactory.setUserAgent(userAgent) + OwnCloudClientManagerFactory.setDefaultPolicy( + if (isSamlAuth) { + Policy.SINGLE_SESSION_PER_ACCOUNT + } else { + Policy.SINGLE_SESSION_PER_ACCOUNT_IF_SERVER_SUPPORTS_SERVER_MONITORING + } + ) + + val oauth2Provider = OwnCloudOAuth2Provider() + oauth2Provider.authorizationCodeEndpointPath = getString(R.string.oauth2_url_endpoint_auth) + oauth2Provider.accessTokenEndpointPath = getString(R.string.oauth2_url_endpoint_access) + oauth2Provider.clientConfiguration = OAuth2ClientConfiguration( + getString(R.string.oauth2_client_id), + getString(R.string.oauth2_client_secret), + getString(R.string.oauth2_redirect_uri) + ) + + OAuth2ProvidersRegistry.getInstance().registerProvider( + OwnCloudOAuth2Provider.NAME, + oauth2Provider + ) + + // initialise thumbnails cache on background thread + ThumbnailsCacheManager.InitDiskCacheTask().execute() + + if (BuildConfig.DEBUG || isBeta) { + + val dataFolder = dataFolder + + // Set folder for store logs + Log_OC.setLogDataFolder(dataFolder) + + Log_OC.startLogging(Environment.getExternalStorageDirectory().absolutePath) + Log_OC.d(BuildConfig.BUILD_TYPE, "start logging " + BuildConfig.VERSION_NAME) + } + + // register global protection with pass code, pattern lock and fingerprint lock + registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + Log_OC.d(activity.javaClass.simpleName, "onCreate(Bundle) starting") + PassCodeManager.getPassCodeManager().onActivityCreated(activity) + PatternManager.getPatternManager().onActivityCreated(activity) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + FingerprintManager.getFingerprintManager(activity).onActivityCreated(activity) + } + // If there's any lock protection, don't show wizard at this point, show it when lock activities + // have finished + if (activity !is PassCodeActivity && + activity !is PatternLockActivity && + activity !is FingerprintActivity + ) { + WhatsNewActivity.runIfNeeded(activity) + } + } + + override fun onActivityStarted(activity: Activity) { + Log_OC.d(activity.javaClass.simpleName, "onStart() starting") + PassCodeManager.getPassCodeManager().onActivityStarted(activity) + PatternManager.getPatternManager().onActivityStarted(activity) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + FingerprintManager.getFingerprintManager(activity).onActivityStarted(activity) + } + } + + override fun onActivityResumed(activity: Activity) { + Log_OC.d(activity.javaClass.simpleName, "onResume() starting") + } + + override fun onActivityPaused(activity: Activity) { + Log_OC.d(activity.javaClass.simpleName, "onPause() ending") + } + + override fun onActivityStopped(activity: Activity) { + Log_OC.d(activity.javaClass.simpleName, "onStop() ending") + PassCodeManager.getPassCodeManager().onActivityStopped(activity) + PatternManager.getPatternManager().onActivityStopped(activity) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + FingerprintManager.getFingerprintManager(activity).onActivityStopped(activity) + } + if (activity is PassCodeActivity || + activity is PatternLockActivity || + activity is FingerprintActivity + ) { + WhatsNewActivity.runIfNeeded(activity) + } + } + + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { + Log_OC.d(activity.javaClass.simpleName, "onSaveInstanceState(Bundle) starting") + } + + override fun onActivityDestroyed(activity: Activity) { + Log_OC.d(activity.javaClass.simpleName, "onDestroy() ending") + } + }) + + val newArchModule = module { + viewModel { (filePath: String, account: Account, shareTypes: List) -> + OCShareViewModel(androidContext(), filePath, account, shareTypes) + } + + viewModel { (account: Account) -> + OCCapabilityViewModel(androidContext(), account) + } + } + + startKoin { + androidContext(applicationContext) + modules(newArchModule) + } + } + + companion object { + private val TAG = MainApp::class.java.simpleName + + private val AUTH_ON = "on" + + var appContext: Context? = null + private set + + var BETA_VERSION = "beta" + + /** + * Next methods give access in code to some constants that need to be defined in string resources to be referred + * in AndroidManifest.xml file or other xml resource files; or that need to be easy to modify in build time. + */ + + val accountType: String + get() = appContext!!.resources.getString(R.string.account_type) + + val versionCode: Int + get() { + try { + val thisPackageName = appContext!!.packageName + return appContext!!.packageManager.getPackageInfo(thisPackageName, 0).versionCode + } catch (e: PackageManager.NameNotFoundException) { + return 0 + } + + } + + val authority: String + get() = appContext!!.resources.getString(R.string.authority) + + val authTokenType: String + get() = appContext!!.resources.getString(R.string.authority) + + val dbFile: String + get() = appContext!!.resources.getString(R.string.db_file) + + val dbName: String + get() = appContext!!.resources.getString(R.string.db_name) + + val dataFolder: String + get() = appContext!!.resources.getString(R.string.data_folder) + + val logName: String + get() = appContext!!.resources.getString(R.string.log_name) + + // user agent + // Mozilla/5.0 (Android) ownCloud-android/1.7.0 + val userAgent: String + get() { + val appString = appContext!!.resources.getString(R.string.user_agent) + val packageName = appContext!!.packageName + var version = "" + + val pInfo: PackageInfo? + try { + pInfo = appContext!!.packageManager.getPackageInfo(packageName, 0) + if (pInfo != null) { + version = pInfo.versionName + } + } catch (e: PackageManager.NameNotFoundException) { + Log_OC.e(TAG, "Trying to get packageName", e.cause) + } + + return String.format(appString, version) + } + + val isBeta: Boolean + get() { + var isBeta = false + try { + val packageName = appContext!!.packageName + val packageInfo = appContext!!.packageManager.getPackageInfo(packageName, 0) + val versionName = packageInfo.versionName + if (versionName.contains(BETA_VERSION)) { + isBeta = true + } + } catch (e: PackageManager.NameNotFoundException) { + e.printStackTrace() + } + + return isBeta + } + } +} diff --git a/owncloudApp/src/main/java/com/owncloud/android/NetworkBoundResource.kt b/owncloudApp/src/main/java/com/owncloud/android/NetworkBoundResource.kt index dd3b635baf1..fae35a4c489 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/NetworkBoundResource.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/NetworkBoundResource.kt @@ -39,6 +39,7 @@ import androidx.annotation.MainThread import androidx.annotation.WorkerThread import androidx.lifecycle.LiveData import androidx.lifecycle.MediatorLiveData +import androidx.lifecycle.MutableLiveData import com.owncloud.android.lib.common.operations.RemoteOperationResult import com.owncloud.android.vo.Resource @@ -58,8 +59,8 @@ abstract class NetworkBoundResource( val dbSource = loadFromDb() result.addSource(dbSource) { data -> result.removeSource(dbSource) - if (shouldFetch(data)) { - performNetworkOperation(dbSource) + if (shouldFetchFromNetwork(data)) { + fetchFromNetwork(dbSource) } else { result.addSource(dbSource) { newData -> setValue(Resource.success(newData)) @@ -75,7 +76,7 @@ abstract class NetworkBoundResource( } } - private fun performNetworkOperation(dbSource: LiveData) { + private fun fetchFromNetwork(dbSource: LiveData) { // Let's dispatch dbSource value quickly while network operation is performed result.addSource(dbSource) { newData -> if (newData != null) { @@ -132,12 +133,13 @@ abstract class NetworkBoundResource( } fun asLiveData() = result as LiveData> + fun asMutableLiveData() = result as MutableLiveData> @WorkerThread protected abstract fun saveCallResult(item: RequestType) @MainThread - protected abstract fun shouldFetch(data: ResultType?): Boolean + protected abstract fun shouldFetchFromNetwork(data: ResultType?): Boolean @MainThread protected abstract fun loadFromDb(): LiveData diff --git a/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountAuthenticator.java b/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountAuthenticator.java index 07a107f72ef..f20b971312c 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountAuthenticator.java +++ b/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountAuthenticator.java @@ -94,7 +94,7 @@ public Bundle addAccount(AccountAuthenticatorResponse response, final Bundle bundle = new Bundle(); AccountManager accountManager = AccountManager.get(mContext); - Account[] accounts = accountManager.getAccountsByType(MainApp.getAccountType()); + Account[] accounts = accountManager.getAccountsByType(MainApp.Companion.getAccountType()); if (mContext.getResources().getBoolean(R.bool.multiaccount_support) || accounts.length < 1) { try { @@ -191,7 +191,7 @@ public Bundle getAuthToken(AccountAuthenticatorResponse response, /// check if required token is stored final AccountManager am = AccountManager.get(mContext); String accessToken; - if (authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType()))) { + if (authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.Companion.getAccountType()))) { accessToken = am.getPassword(account); } else { // Gets an auth token from the AccountManager's cache. If no auth token is cached for @@ -204,7 +204,7 @@ public Bundle getAuthToken(AccountAuthenticatorResponse response, if (accessToken != null) { final Bundle result = new Bundle(); result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); - result.putString(AccountManager.KEY_ACCOUNT_TYPE, MainApp.getAccountType()); + result.putString(AccountManager.KEY_ACCOUNT_TYPE, MainApp.Companion.getAccountType()); result.putString(AccountManager.KEY_AUTHTOKEN, accessToken); return result; } @@ -266,18 +266,18 @@ private void setIntentFlags(Intent intent) { private void validateAccountType(String type) throws UnsupportedAccountTypeException { - if (!type.equals(MainApp.getAccountType())) { + if (!type.equals(MainApp.Companion.getAccountType())) { throw new UnsupportedAccountTypeException(); } } private void validateAuthTokenType(String authTokenType) throws UnsupportedAuthTokenTypeException { - if (!authTokenType.equals(MainApp.getAuthTokenType()) && - !authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType())) && - !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType())) && - !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeRefreshToken(MainApp.getAccountType())) && - !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()))) { + if (!authTokenType.equals(MainApp.Companion.getAuthTokenType()) && + !authTokenType.equals(AccountTypeUtils.getAuthTokenTypePass(MainApp.Companion.getAccountType())) && + !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.Companion.getAccountType())) && + !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeRefreshToken(MainApp.Companion.getAccountType())) && + !authTokenType.equals(AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()))) { throw new UnsupportedAuthTokenTypeException(); } } @@ -319,7 +319,7 @@ public UnsupportedAuthTokenTypeException() { } private boolean canBeRefreshed(String authTokenType) { - return (authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp. + return (authTokenType.equals(AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.Companion. getAccountType()))); } diff --git a/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountUtils.java b/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountUtils.java index 7f6b507c748..b8c6d8327d9 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountUtils.java +++ b/owncloudApp/src/main/java/com/owncloud/android/authentication/AccountUtils.java @@ -85,7 +85,7 @@ public static Account getCurrentOwnCloudAccount(Context context) { public static Account[] getAccounts(Context context) { AccountManager accountManager = AccountManager.get(context); - return accountManager.getAccountsByType(MainApp.getAccountType()); + return accountManager.getAccountsByType(MainApp.Companion.getAccountType()); } public static boolean exists(String accountName, Context context) { @@ -133,7 +133,7 @@ public static String getUsernameOfAccount(String accountName) { */ public static Account getOwnCloudAccountByName(Context context, String accountName) { Account[] ocAccounts = AccountManager.get(context).getAccountsByType( - MainApp.getAccountType()); + MainApp.Companion.getAccountType()); for (Account account : ocAccounts) { if (account.name.equals(accountName)) { return account; @@ -174,10 +174,10 @@ public static boolean setCurrentOwnCloudAccount(Context context, String accountN */ public static String getWebdavPath(OwnCloudVersion version, String authTokenType) { if (version != null) { - if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(authTokenType)) { + if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.Companion.getAccountType()).equals(authTokenType)) { return ODAV_PATH; } - if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(authTokenType)) { + if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()).equals(authTokenType)) { return SAML_SSO_PATH; } return WEBDAV_PATH_4_0_AND_LATER; @@ -202,7 +202,7 @@ public static void updateAccountVersion(Context context) { if (currentAccountVersion == null) { Log_OC.i(TAG, "Upgrading accounts to account version #" + ACCOUNT_VERSION); - Account[] ocAccounts = accountMgr.getAccountsByType(MainApp.getAccountType()); + Account[] ocAccounts = accountMgr.getAccountsByType(MainApp.Companion.getAccountType()); String serverUrl, username, newAccountName, password; Account newAccount; for (Account account : ocAccounts) { @@ -218,7 +218,7 @@ public static void updateAccountVersion(Context context) { Log_OC.d(TAG, "Upgrading " + account.name + " to " + newAccountName); // create the new account - newAccount = new Account(newAccountName, MainApp.getAccountType()); + newAccount = new Account(newAccountName, MainApp.Companion.getAccountType()); password = accountMgr.getPassword(account); accountMgr.addAccountExplicitly(newAccount, (password != null) ? password : "", null); @@ -312,9 +312,9 @@ public static OwnCloudVersion getServerVersion(Account account) { if (account != null) { // capabilities are now the preferred source for version info FileDataStorageManager fileDataStorageManager = new FileDataStorageManager( - MainApp.getAppContext(), + MainApp.Companion.getAppContext(), account, - MainApp.getAppContext().getContentResolver() + MainApp.Companion.getAppContext().getContentResolver() ); RemoteCapability capability = fileDataStorageManager.getCapability(account.name); if (capability != null) { @@ -322,7 +322,7 @@ public static OwnCloudVersion getServerVersion(Account account) { } else { // legacy: AccountManager as source of version info - AccountManager accountMgr = AccountManager.get(MainApp.getAppContext()); + AccountManager accountMgr = AccountManager.get(MainApp.Companion.getAppContext()); String serverVersionStr = accountMgr.getUserData(account, Constants.KEY_OC_VERSION); if (serverVersionStr != null) { serverVersion = new OwnCloudVersion(serverVersionStr); diff --git a/owncloudApp/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java b/owncloudApp/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java index 1f54b78b987..b79cc533821 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java @@ -227,11 +227,11 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity private long mWaitingForOpId = Long.MAX_VALUE; private final String BASIC_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypePass( - MainApp.getAccountType()); + MainApp.Companion.getAccountType()); private final String OAUTH_TOKEN_TYPE = AccountTypeUtils.getAuthTokenTypeAccessToken( - MainApp.getAccountType()); + MainApp.Companion.getAccountType()); private final String SAML_TOKEN_TYPE = - AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()); + AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()); private CustomTabsClient mCustomTabsClient; private CustomTabsServiceConnection mCustomTabServiceConnection = new CustomTabsServiceConnection() { @@ -436,11 +436,11 @@ private void initOverallUi() { String instructionsMessageText = null; if (mAction == ACTION_UPDATE_EXPIRED_TOKEN) { - if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()) + if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.Companion.getAccountType()) .equals(mAuthTokenType)) { instructionsMessageText = getString(R.string.auth_expired_oauth_token_toast); - } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()) + } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()) .equals(mAuthTokenType)) { instructionsMessageText = getString(R.string.auth_expired_saml_sso_token_toast); @@ -665,7 +665,7 @@ public boolean onDrawableTouch(final MotionEvent event) { * the current authorization method. */ private void updateAuthenticationPreFragmentVisibility() { - if (AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType()). + if (AccountTypeUtils.getAuthTokenTypePass(MainApp.Companion.getAccountType()). equals(mAuthTokenType)) { // basic HTTP authorization mUsernameInput.setVisibility(View.VISIBLE); @@ -1028,10 +1028,10 @@ public void onLoginClick() { return; } - if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()). + if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.Companion.getAccountType()). equals(mAuthTokenType)) { startOauthorization(); - } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()). + } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()). equals(mAuthTokenType)) { startSamlBasedFederatedSingleSignOnAuthorization(); } else { @@ -1565,9 +1565,9 @@ public void onAuthenticatorTaskCallback(RemoteOperationResult result) { private boolean createAccount(RemoteOperationResult authResult) { /// create and save new ownCloud account boolean isOAuth = AccountTypeUtils. - getAuthTokenTypeAccessToken(MainApp.getAccountType()).equals(mAuthTokenType); + getAuthTokenTypeAccessToken(MainApp.Companion.getAccountType()).equals(mAuthTokenType); boolean isSaml = AccountTypeUtils. - getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()).equals(mAuthTokenType); + getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()).equals(mAuthTokenType); String lastPermanentLocation = authResult.getLastPermanentLocation(); if (lastPermanentLocation != null) { @@ -1578,7 +1578,7 @@ private boolean createAccount(RemoteOperationResult authResult) { String username = mUsernameInput.getText().toString().trim(); String accountName = com.owncloud.android.lib.common.accounts.AccountUtils. buildAccountName(uri, username); - Account newAccount = new Account(accountName, MainApp.getAccountType()); + Account newAccount = new Account(accountName, MainApp.Companion.getAccountType()); if (AccountUtils.exists(newAccount.name, getApplicationContext())) { // fail - not a new account, but an existing one; disallow RemoteOperationResult result = new RemoteOperationResult(ResultCode.ACCOUNT_NOT_NEW); @@ -1619,7 +1619,7 @@ private boolean createAccount(RemoteOperationResult authResult) { // TODO check again what the Authenticator makes with it; probably has the same // effect as addAccountExplicitly, but it's not well done final Intent intent = new Intent(); - intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, MainApp.getAccountType()); + intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, MainApp.Companion.getAccountType()); intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, mAccount.name); intent.putExtra(AccountManager.KEY_USERDATA, username); if (isOAuth || isSaml) { @@ -1718,7 +1718,7 @@ private void updateAccountAuthentication() throws AccountNotFoundException { String SAMLSupported = mAccountMgr.getUserData(mAccount, Constants. KEY_SUPPORTS_SAML_WEB_SSO); - if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.getAccountType()). + if (AccountTypeUtils.getAuthTokenTypeAccessToken(MainApp.Companion.getAccountType()). equals(mAuthTokenType)) { // OAuth response.putString(AccountManager.KEY_AUTHTOKEN, mAuthToken); // the next line is necessary, notifications are calling directly to the @@ -1735,7 +1735,7 @@ private void updateAccountAuthentication() throws AccountNotFoundException { mAccountMgr.setUserData(mAccount, Constants.KEY_SUPPORTS_SAML_WEB_SSO, "FALSE"); } - } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()). + } else if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()). equals(mAuthTokenType)) { // SAML if (SAMLSupported == null || SAMLSupported != null && SAMLSupported.equals("FALSE")) { @@ -1865,7 +1865,7 @@ public boolean onEditorAction(TextView inputField, int actionId, KeyEvent event) } else if (actionId == EditorInfo.IME_ACTION_NEXT && inputField != null && inputField.equals(mHostUrlInput)) { - if (!AccountTypeUtils.getAuthTokenTypePass(MainApp.getAccountType()). + if (!AccountTypeUtils.getAuthTokenTypePass(MainApp.Companion.getAccountType()). equals(mAuthTokenType)) { checkOcServer(); } @@ -1940,7 +1940,7 @@ public void onSsoFinished(String sessionCookie) { @Override public boolean onTouchEvent(MotionEvent event) { - if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.getAccountType()). + if (AccountTypeUtils.getAuthTokenTypeSamlSessionCookie(MainApp.Companion.getAccountType()). equals(mAuthTokenType) && mHostUrlInput.hasFocus() && event.getAction() == MotionEvent.ACTION_DOWN) { checkOcServer(); diff --git a/owncloudApp/src/main/java/com/owncloud/android/authentication/FingerprintManager.java b/owncloudApp/src/main/java/com/owncloud/android/authentication/FingerprintManager.java index b092a222287..bf0a98d3ef5 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/authentication/FingerprintManager.java +++ b/owncloudApp/src/main/java/com/owncloud/android/authentication/FingerprintManager.java @@ -106,7 +106,7 @@ public void onActivityStarted(Activity activity) { return; } - Intent i = new Intent(MainApp.getAppContext(), FingerprintActivity.class); + Intent i = new Intent(MainApp.Companion.getAppContext(), FingerprintActivity.class); activity.startActivity(i); } } @@ -140,7 +140,7 @@ private boolean fingerprintShouldBeRequested() { } public boolean isFingerPrintEnabled() { - SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext()); + SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.Companion.getAppContext()); return (appPrefs.getBoolean(FingerprintActivity.PREFERENCE_SET_FINGERPRINT, false)); } diff --git a/owncloudApp/src/main/java/com/owncloud/android/authentication/PassCodeManager.java b/owncloudApp/src/main/java/com/owncloud/android/authentication/PassCodeManager.java index 1e438a55f81..e6c7a71626a 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/authentication/PassCodeManager.java +++ b/owncloudApp/src/main/java/com/owncloud/android/authentication/PassCodeManager.java @@ -107,7 +107,7 @@ public void onFingerprintCancelled(Activity activity) { } private void checkPasscode(Activity activity) { - Intent i = new Intent(MainApp.getAppContext(), PassCodeActivity.class); + Intent i = new Intent(MainApp.Companion.getAppContext(), PassCodeActivity.class); i.setAction(PassCodeActivity.ACTION_CHECK); i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); activity.startActivity(i); @@ -126,7 +126,7 @@ private boolean passCodeShouldBeRequested() { } public boolean isPassCodeEnabled() { - SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext()); + SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.Companion.getAppContext()); return (appPrefs.getBoolean(PassCodeActivity.PREFERENCE_SET_PASSCODE, false)); } diff --git a/owncloudApp/src/main/java/com/owncloud/android/authentication/PatternManager.java b/owncloudApp/src/main/java/com/owncloud/android/authentication/PatternManager.java index ede414abb39..1d4d8d3f88c 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/authentication/PatternManager.java +++ b/owncloudApp/src/main/java/com/owncloud/android/authentication/PatternManager.java @@ -105,7 +105,7 @@ public void onFingerprintCancelled(Activity activity) { } private void checkPattern(Activity activity) { - Intent i = new Intent(MainApp.getAppContext(), PatternLockActivity.class); + Intent i = new Intent(MainApp.Companion.getAppContext(), PatternLockActivity.class); i.setAction(PatternLockActivity.ACTION_CHECK); activity.startActivity(i); } @@ -120,7 +120,7 @@ private boolean patternShouldBeRequested() { } public boolean isPatternEnabled() { - SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext()); + SharedPreferences appPrefs = PreferenceManager.getDefaultSharedPreferences(MainApp.Companion.getAppContext()); return appPrefs.getBoolean(PatternLockActivity.PREFERENCE_SET_PATTERN, false); } diff --git a/owncloudApp/src/main/java/com/owncloud/android/broadcastreceivers/ConnectivityActionReceiver.java b/owncloudApp/src/main/java/com/owncloud/android/broadcastreceivers/ConnectivityActionReceiver.java index 2d62ff69ba6..ddc1b142ee6 100755 --- a/owncloudApp/src/main/java/com/owncloud/android/broadcastreceivers/ConnectivityActionReceiver.java +++ b/owncloudApp/src/main/java/com/owncloud/android/broadcastreceivers/ConnectivityActionReceiver.java @@ -173,7 +173,7 @@ private void wifiConnected(Context context) { //by using jobs in versions 5 or higher if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) { requester.retryFailedUploads( - MainApp.getAppContext(), + MainApp.Companion.getAppContext(), null, // for the interrupted when Wifi fell, if any // (side effect: any upload failed due to network error will be @@ -184,7 +184,7 @@ private void wifiConnected(Context context) { } requester.retryFailedUploads( - MainApp.getAppContext(), + MainApp.Companion.getAppContext(), null, UploadResult.DELAYED_FOR_WIFI, // for the rest of enqueued when Wifi fell true diff --git a/owncloudApp/src/main/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSource.kt b/owncloudApp/src/main/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSource.kt index 5b0c5a48823..4fd670cd380 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSource.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/capabilities/datasource/OCLocalCapabilitiesDataSource.kt @@ -19,14 +19,15 @@ package com.owncloud.android.capabilities.datasource +import android.content.Context import androidx.lifecycle.LiveData -import com.owncloud.android.MainApp import com.owncloud.android.capabilities.db.OCCapability import com.owncloud.android.capabilities.db.OCCapabilityDao import com.owncloud.android.db.OwncloudDatabase class OCLocalCapabilitiesDataSource( - private val ocCapabilityDao: OCCapabilityDao = OwncloudDatabase.getDatabase(MainApp.getAppContext()).capabilityDao() + context: Context, + private val ocCapabilityDao: OCCapabilityDao = OwncloudDatabase.getDatabase(context).capabilityDao() ) : LocalCapabilitiesDataSource { override fun getCapabilityForAccountAsLiveData(accountName: String): LiveData = diff --git a/owncloudApp/src/main/java/com/owncloud/android/capabilities/repository/OCCapabilityRepository.kt b/owncloudApp/src/main/java/com/owncloud/android/capabilities/repository/OCCapabilityRepository.kt index 148fd7417d5..261b9ccc455 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/capabilities/repository/OCCapabilityRepository.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/capabilities/repository/OCCapabilityRepository.kt @@ -26,8 +26,10 @@ import com.owncloud.android.capabilities.datasource.LocalCapabilitiesDataSource import com.owncloud.android.capabilities.datasource.RemoteCapabilitiesDataSource import com.owncloud.android.capabilities.db.OCCapability import com.owncloud.android.lib.resources.status.RemoteCapability +import com.owncloud.android.testing.OpenForTesting import com.owncloud.android.vo.Resource +@OpenForTesting class OCCapabilityRepository( private val appExecutors: AppExecutors, private val localCapabilitiesDataSource: LocalCapabilitiesDataSource, @@ -56,7 +58,7 @@ class OCCapabilityRepository( localCapabilitiesDataSource.insert(listOf(OCCapability.fromRemoteCapability(item))) } - override fun shouldFetch(data: OCCapability?) = shouldFetchFromNetwork + override fun shouldFetchFromNetwork(data: OCCapability?) = shouldFetchFromNetwork override fun loadFromDb(): LiveData = localCapabilitiesDataSource.getCapabilityForAccountAsLiveData(accountName) diff --git a/owncloudApp/src/main/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModel.kt index c6510dd09f1..356b2d3278a 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/capabilities/viewmodel/OCCapabilityViewModel.kt @@ -20,9 +20,9 @@ package com.owncloud.android.capabilities.viewmodel import android.accounts.Account +import android.content.Context import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel -import com.owncloud.android.MainApp import com.owncloud.android.capabilities.datasource.OCLocalCapabilitiesDataSource import com.owncloud.android.capabilities.datasource.OCRemoteCapabilitiesDataSource import com.owncloud.android.capabilities.db.OCCapability @@ -39,18 +39,18 @@ import com.owncloud.android.vo.Resource @OpenForTesting class OCCapabilityViewModel( + context: Context, val account: Account, val capabilityRepository: CapabilityRepository = OCCapabilityRepository.create( - localCapabilitiesDataSource = OCLocalCapabilitiesDataSource(), + localCapabilitiesDataSource = OCLocalCapabilitiesDataSource(context), remoteCapabilitiesDataSource = OCRemoteCapabilitiesDataSource( OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor( - OwnCloudAccount(account, MainApp.getAppContext()), - MainApp.getAppContext() + OwnCloudAccount(account, context), + context ) ) ) ) : ViewModel() { - fun getCapabilityForAccount(shouldFetchFromNetwork: Boolean = true): LiveData> = capabilityRepository.loadCapabilityForAccount(account.name, shouldFetchFromNetwork) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java b/owncloudApp/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java index 74e705bcc93..645ee597ffc 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java +++ b/owncloudApp/src/main/java/com/owncloud/android/datamodel/FileDataStorageManager.java @@ -429,7 +429,7 @@ public void saveFolder( Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); try { if (getContentResolver() != null) { - results = getContentResolver().applyBatch(MainApp.getAuthority(), operations); + results = getContentResolver().applyBatch(MainApp.Companion.getAuthority(), operations); } else { results = getContentProviderClient().applyBatch(operations); @@ -830,7 +830,7 @@ public void moveLocalFile(OCFile file, String targetPath, String targetParentPat /// 3. apply updates in batch try { if (getContentResolver() != null) { - getContentResolver().applyBatch(MainApp.getAuthority(), operations); + getContentResolver().applyBatch(MainApp.Companion.getAuthority(), operations); } else { getContentProviderClient().applyBatch(operations); @@ -1451,7 +1451,7 @@ public void saveShares(List shares) { Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); try { if (getContentResolver() != null) { - getContentResolver().applyBatch(MainApp.getAuthority(), operations); + getContentResolver().applyBatch(MainApp.Companion.getAuthority(), operations); } else { getContentProviderClient().applyBatch(operations); @@ -1476,7 +1476,7 @@ public void removeSharesForFile(String remotePath) { Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); try { if (getContentResolver() != null) { - getContentResolver().applyBatch(MainApp.getAuthority(), operations); + getContentResolver().applyBatch(MainApp.Companion.getAuthority(), operations); } else { getContentProviderClient().applyBatch(operations); @@ -1506,7 +1506,7 @@ public void saveSharesInFolder(ArrayList shares, OCFile folder) { Log_OC.d(TAG, "Sending " + operations.size() + " operations to FileContentProvider"); try { if (getContentResolver() != null) { - getContentResolver().applyBatch(MainApp.getAuthority(), operations); + getContentResolver().applyBatch(MainApp.Companion.getAuthority(), operations); } else { @@ -1707,7 +1707,7 @@ public void triggerMediaScan(String path) { } catch (IllegalArgumentException illegalArgumentException) { intent.setData(Uri.fromFile(new File(path))); } - MainApp.getAppContext().sendBroadcast(intent); + MainApp.Companion.getAppContext().sendBroadcast(intent); } } diff --git a/owncloudApp/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java b/owncloudApp/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java index 0e81695ec1a..24d17368518 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java +++ b/owncloudApp/src/main/java/com/owncloud/android/datamodel/ThumbnailsCacheManager.java @@ -75,7 +75,7 @@ public class ThumbnailsCacheManager { public static Bitmap mDefaultImg = BitmapFactory.decodeResource( - MainApp.getAppContext().getResources(), + MainApp.Companion.getAppContext().getResources(), R.drawable.file_image ); @@ -91,7 +91,7 @@ protected Void doInBackground(File... params) { // Check if media is mounted or storage is built-in, if so, // try and use external cache dir; otherwise use internal cache dir final String cachePath = - MainApp.getAppContext().getExternalCacheDir().getPath() + + MainApp.Companion.getAppContext().getExternalCacheDir().getPath() + File.separator + CACHE_FOLDER; Log_OC.d(TAG, "create dir: " + cachePath); final File diskCacheDir = new File(cachePath); @@ -176,10 +176,10 @@ protected Bitmap doInBackground(Object... params) { if (mAccount != null) { OwnCloudAccount ocAccount = new OwnCloudAccount( mAccount, - MainApp.getAppContext() + MainApp.Companion.getAppContext() ); mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, MainApp.getAppContext()); + getClientFor(ocAccount, MainApp.Companion.getAppContext()); } mFile = params[0]; @@ -247,7 +247,7 @@ private Bitmap addThumbnailToCache(String imageKey, Bitmap bitmap, String path, */ private int getThumbnailDimension() { // Converts dp to pixel - Resources r = MainApp.getAppContext().getResources(); + Resources r = MainApp.Companion.getAppContext().getResources(); return Math.round(r.getDimension(R.dimen.file_icon_size_grid)); } @@ -331,7 +331,7 @@ private Bitmap handlePNG(Bitmap bitmap, int px) { Bitmap.Config.ARGB_8888); Canvas c = new Canvas(resultBitmap); - c.drawColor(ContextCompat.getColor(MainApp.getAppContext(), R.color.background_color)); + c.drawColor(ContextCompat.getColor(MainApp.Companion.getAppContext(), R.color.background_color)); c.drawBitmap(bitmap, 0, 0, null); return resultBitmap; @@ -431,9 +431,9 @@ protected Drawable doInBackground(Object... params) { try { OwnCloudAccount ocAccount = new OwnCloudAccount(mAccount, - MainApp.getAppContext()); + MainApp.Companion.getAppContext()); mClient = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, MainApp.getAppContext()); + getClientFor(ocAccount, MainApp.Companion.getAppContext()); mUsername = mAccount.name; thumbnail = doAvatarInBackground(); @@ -484,7 +484,7 @@ protected void onPostExecute(Drawable avatar) { */ private int getAvatarDimension() { // Converts dp to pixel - Resources r = MainApp.getAppContext().getResources(); + Resources r = MainApp.Companion.getAppContext().getResources(); return Math.round(r.getDimension(R.dimen.file_avatar_size)); } @@ -499,7 +499,7 @@ private Drawable doAvatarInBackground() { if (avatarBitmap != null) { avatarDrawable = BitmapUtils.bitmapToCircularBitmapDrawable( - MainApp.getAppContext().getResources(), + MainApp.Companion.getAppContext().getResources(), avatarBitmap ); @@ -541,7 +541,7 @@ private Drawable doAvatarInBackground() { } if (avatarBitmap != null) { avatarDrawable = BitmapUtils.bitmapToCircularBitmapDrawable( - MainApp.getAppContext().getResources(), + MainApp.Companion.getAppContext().getResources(), avatarBitmap ); diff --git a/owncloudApp/src/main/java/com/owncloud/android/datamodel/UserProfilesRepository.java b/owncloudApp/src/main/java/com/owncloud/android/datamodel/UserProfilesRepository.java index b4c3ace3c79..b51f749155e 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/datamodel/UserProfilesRepository.java +++ b/owncloudApp/src/main/java/com/owncloud/android/datamodel/UserProfilesRepository.java @@ -314,7 +314,7 @@ private boolean quotaExists(UserProfile userProfile) { */ private SQLiteDatabase getSqLiteDatabase() { - File dbFile = MainApp.getAppContext().getDatabasePath(ProviderMeta.DB_NAME); + File dbFile = MainApp.Companion.getAppContext().getDatabasePath(ProviderMeta.DB_NAME); if (database == null) { diff --git a/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java b/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java index 7ac256bf4aa..0fd3f03745d 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java +++ b/owncloudApp/src/main/java/com/owncloud/android/db/ProviderMeta.java @@ -50,21 +50,21 @@ static public class ProviderTableMeta implements BaseColumns { public static final String USER_QUOTAS_TABLE_NAME = "user_quotas"; public static final Uri CONTENT_URI = Uri.parse("content://" - + MainApp.getAuthority() + "/"); + + MainApp.Companion.getAuthority() + "/"); public static final Uri CONTENT_URI_FILE = Uri.parse("content://" - + MainApp.getAuthority() + "/file"); + + MainApp.Companion.getAuthority() + "/file"); public static final Uri CONTENT_URI_DIR = Uri.parse("content://" - + MainApp.getAuthority() + "/dir"); + + MainApp.Companion.getAuthority() + "/dir"); public static final Uri CONTENT_URI_SHARE = Uri.parse("content://" - + MainApp.getAuthority() + "/shares"); + + MainApp.Companion.getAuthority() + "/shares"); public static final Uri CONTENT_URI_CAPABILITIES = Uri.parse("content://" - + MainApp.getAuthority() + "/capabilities"); + + MainApp.Companion.getAuthority() + "/capabilities"); public static final Uri CONTENT_URI_UPLOADS = Uri.parse("content://" - + MainApp.getAuthority() + "/uploads"); + + MainApp.Companion.getAuthority() + "/uploads"); public static final Uri CONTENT_URI_CAMERA_UPLOADS_SYNC = Uri.parse("content://" - + MainApp.getAuthority() + "/cameraUploadsSync"); + + MainApp.Companion.getAuthority() + "/cameraUploadsSync"); public static final Uri CONTENT_URI_QUOTAS = Uri.parse("content://" - + MainApp.getAuthority() + "/quotas"); + + MainApp.Companion.getAuthority() + "/quotas"); public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.owncloud.file"; public static final String CONTENT_TYPE_ITEM = "vnd.android.cursor.item/vnd.owncloud.file"; diff --git a/owncloudApp/src/main/java/com/owncloud/android/features/FeatureList.java b/owncloudApp/src/main/java/com/owncloud/android/features/FeatureList.java index 8eb2229e412..7e09c4a8903 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/features/FeatureList.java +++ b/owncloudApp/src/main/java/com/owncloud/android/features/FeatureList.java @@ -79,7 +79,7 @@ static public FeatureItem[] getFiltered(final int lastSeenVersionCode, final boo if (isFirstRun && item.shouldShowOnFirstRun()) { features.add(item); } else if (!isFirstRun && !item.shouldShowOnFirstRun() && - MainApp.getVersionCode() >= itemVersionCode && + MainApp.Companion.getVersionCode() >= itemVersionCode && lastSeenVersionCode < itemVersionCode) { features.add(item); } diff --git a/owncloudApp/src/main/java/com/owncloud/android/files/services/AvailableOfflineSyncJobService.java b/owncloudApp/src/main/java/com/owncloud/android/files/services/AvailableOfflineSyncJobService.java index 2e0ea8afdf0..182ec416271 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/files/services/AvailableOfflineSyncJobService.java +++ b/owncloudApp/src/main/java/com/owncloud/android/files/services/AvailableOfflineSyncJobService.java @@ -119,7 +119,7 @@ private void syncAvailableOfflineFiles(List> availableOffli File localFile = new File(localPath); if (localFile.lastModified() <= fileForAccount.first.getLastSyncDateForData() && - (BuildConfig.DEBUG || MainApp.isBeta())) { + (BuildConfig.DEBUG || MainApp.Companion.isBeta())) { Log_OC.i(TAG, "File " + fileForAccount.first.getRemotePath() + " already synchronized " + "in account " + fileForAccount.second + ", ignoring"); continue; @@ -136,7 +136,7 @@ private void syncAvailableOfflineFiles(List> availableOffli * @param accountName account to synchronize the available offline file with */ private void startSyncOperation(OCFile availableOfflineFile, String accountName) { - if (BuildConfig.DEBUG || MainApp.isBeta()) { + if (BuildConfig.DEBUG || MainApp.Companion.isBeta()) { Log_OC.i( TAG, String.format( diff --git a/owncloudApp/src/main/java/com/owncloud/android/operations/GetUserProfileOperation.java b/owncloudApp/src/main/java/com/owncloud/android/operations/GetUserProfileOperation.java index 2e88619ff7c..79fcb2bc6eb 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/operations/GetUserProfileOperation.java +++ b/owncloudApp/src/main/java/com/owncloud/android/operations/GetUserProfileOperation.java @@ -83,7 +83,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { if (userInfoOperationResult.isSuccess()) { // store display name with account data - AccountManager accountManager = AccountManager.get(MainApp.getAppContext()); + AccountManager accountManager = AccountManager.get(MainApp.Companion.getAppContext()); UserInfo userInfo = userInfoOperationResult.getData(); Account storedAccount = getStorageManager().getAccount(); accountManager.setUserData( @@ -187,7 +187,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { */ private int getAvatarDimension() { // Converts dp to pixel - Resources r = MainApp.getAppContext().getResources(); + Resources r = MainApp.Companion.getAppContext().getResources(); return Math.round(r.getDimension(R.dimen.file_avatar_size)); } } \ No newline at end of file diff --git a/owncloudApp/src/main/java/com/owncloud/android/operations/SyncCapabilitiesOperation.java b/owncloudApp/src/main/java/com/owncloud/android/operations/SyncCapabilitiesOperation.java index b924f1a010b..07b41c7209a 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/operations/SyncCapabilitiesOperation.java +++ b/owncloudApp/src/main/java/com/owncloud/android/operations/SyncCapabilitiesOperation.java @@ -57,7 +57,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { // server version is important; this fallback will try to get it from status.php // if capabilities API is not available - GetRemoteStatusOperation getStatus = new GetRemoteStatusOperation(MainApp.getAppContext()); + GetRemoteStatusOperation getStatus = new GetRemoteStatusOperation(MainApp.Companion.getAppContext()); RemoteOperationResult statusResult = getStatus.execute(client); if (statusResult.isSuccess()) { serverVersion = statusResult.getData(); @@ -74,7 +74,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { // library: com.owncloud.android.lib.common.accounts.AccountUtils#getCredentialsForAccount(...) // and com.owncloud.android.lib.common.accounts.AccountUtils#getServerVersionForAccount(...) if (serverVersion != null) { - AccountManager accountMngr = AccountManager.get(MainApp.getAppContext()); + AccountManager accountMngr = AccountManager.get(MainApp.Companion.getAppContext()); accountMngr.setUserData( getStorageManager().getAccount(), com.owncloud.android.lib.common.accounts.AccountUtils.Constants.KEY_OC_VERSION, diff --git a/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java b/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java index 12832e80603..06b32751c68 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java +++ b/owncloudApp/src/main/java/com/owncloud/android/operations/SynchronizeFileOperation.java @@ -221,7 +221,7 @@ protected RemoteOperationResult run(OwnCloudClient client) { } } - if (BuildConfig.DEBUG || MainApp.isBeta()) { + if (BuildConfig.DEBUG || MainApp.Companion.isBeta()) { Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", file " + mLocalFile.getRemotePath() + ": " + result.getLogMessage()); } diff --git a/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt b/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt index a6ad66f9211..8cd32b51c17 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/providers/FileContentProvider.kt @@ -945,7 +945,7 @@ class FileContentProvider(val appExecutors: AppExecutors = AppExecutors()) : Con // Insert share list to the new shares table in new database appExecutors.diskIO().execute { - OCLocalSharesDataSource().insert(shares) + OCLocalSharesDataSource(context).insert(shares) } // Drop old shares table from old database @@ -968,7 +968,7 @@ class FileContentProvider(val appExecutors: AppExecutors = AppExecutors()) : Con if (cursor.moveToFirst()) { // Insert capability to the new capabilities table in new database appExecutors.diskIO().execute { - OCLocalCapabilitiesDataSource().insert( + OCLocalCapabilitiesDataSource(context).insert( listOf(OCCapability.fromCursor(cursor)) ) } @@ -1152,7 +1152,7 @@ class FileContentProvider(val appExecutors: AppExecutors = AppExecutors()) : Con // we know the update was previously done in {link @FileActivity#onCreate} because the changes through // AccountManager are not synchronous val accounts = AccountManager.get(context).getAccountsByType( - MainApp.getAccountType() + MainApp.accountType ) var serverUrl: String var username: String? diff --git a/owncloudApp/src/main/java/com/owncloud/android/services/OperationsService.java b/owncloudApp/src/main/java/com/owncloud/android/services/OperationsService.java index 531141fa96d..03fc7136fa7 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/services/OperationsService.java +++ b/owncloudApp/src/main/java/com/owncloud/android/services/OperationsService.java @@ -223,7 +223,7 @@ public void onDestroy() { // Saving cookies try { OwnCloudClientManagerFactory.getDefaultSingleton(). - saveAllClients(this, MainApp.getAccountType()); + saveAllClients(this, MainApp.Companion.getAccountType()); // TODO - get rid of these exceptions } catch ( diff --git a/owncloudApp/src/main/java/com/owncloud/android/shares/datasource/OCLocalSharesDataSource.kt b/owncloudApp/src/main/java/com/owncloud/android/shares/datasource/OCLocalSharesDataSource.kt index c2c1b3a1b49..6c9fbe46ff5 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/shares/datasource/OCLocalSharesDataSource.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/shares/datasource/OCLocalSharesDataSource.kt @@ -19,15 +19,16 @@ package com.owncloud.android.shares.datasource +import android.content.Context import androidx.lifecycle.LiveData -import com.owncloud.android.MainApp import com.owncloud.android.db.OwncloudDatabase import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.shares.db.OCShare import com.owncloud.android.shares.db.OCShareDao class OCLocalSharesDataSource( - private val ocShareDao: OCShareDao = OwncloudDatabase.getDatabase(MainApp.getAppContext()).shareDao() + context: Context, + private val ocShareDao: OCShareDao = OwncloudDatabase.getDatabase(context).shareDao() ) : LocalSharesDataSource { override fun getSharesForFileAsLiveData( diff --git a/owncloudApp/src/main/java/com/owncloud/android/shares/repository/OCShareRepository.kt b/owncloudApp/src/main/java/com/owncloud/android/shares/repository/OCShareRepository.kt index 8ec3fcc8e00..6d94632d147 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/shares/repository/OCShareRepository.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/shares/repository/OCShareRepository.kt @@ -20,6 +20,7 @@ package com.owncloud.android.shares.repository import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import com.owncloud.android.AppExecutors import com.owncloud.android.NetworkBoundResource import com.owncloud.android.lib.resources.shares.ShareParserResult @@ -27,38 +28,20 @@ import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.shares.datasource.LocalSharesDataSource import com.owncloud.android.shares.datasource.RemoteSharesDataSource import com.owncloud.android.shares.db.OCShare +import com.owncloud.android.testing.OpenForTesting import com.owncloud.android.vo.Resource +@OpenForTesting class OCShareRepository( - private val appExecutors: AppExecutors, + private val appExecutors: AppExecutors = AppExecutors(), private val localSharesDataSource: LocalSharesDataSource, private val remoteSharesDataSource: RemoteSharesDataSource, val filePath: String, - val accountName: String + val accountName: String, + val shareTypes: List ) : ShareRepository { - - companion object Factory { - fun create( - appExecutors: AppExecutors = AppExecutors(), - localSharesDataSource: LocalSharesDataSource, - remoteSharesDataSource: RemoteSharesDataSource, - filePathToShare: String, - accountName: String - ): OCShareRepository = OCShareRepository( - appExecutors, - localSharesDataSource, - remoteSharesDataSource, - filePathToShare, - accountName - ) - } - - override fun loadSharesForFile( - shareTypes: List, - reshares: Boolean, - subfiles: Boolean - ): LiveData>> { - return object : NetworkBoundResource, ShareParserResult>(appExecutors) { + private val sharesForFile: MutableLiveData>> = + object : NetworkBoundResource, ShareParserResult>(appExecutors) { override fun saveCallResult(item: ShareParserResult) { val sharesForFileFromServer = item.shares.map { remoteShare -> OCShare.fromRemoteShare(remoteShare).also { it.accountOwner = accountName } @@ -71,15 +54,17 @@ class OCShareRepository( localSharesDataSource.replaceSharesForFile(sharesForFileFromServer) } - override fun shouldFetch(data: List?) = true + override fun shouldFetchFromNetwork(data: List?) = true override fun loadFromDb(): LiveData> = localSharesDataSource.getSharesForFileAsLiveData(filePath, accountName, shareTypes) override fun createCall() = - remoteSharesDataSource.getSharesForFile(filePath, reshares, subfiles) + remoteSharesDataSource.getSharesForFile(filePath, reshares = true, subfiles = false) + }.asMutableLiveData() - }.asLiveData() + override fun getSharesForFile(): LiveData>> { + return sharesForFile } override fun insertPublicShareForFile( @@ -88,25 +73,13 @@ class OCShareRepository( password: String, expirationTimeInMillis: Long, publicUpload: Boolean - ): LiveData>> { - return object : NetworkBoundResource, ShareParserResult>(appExecutors) { - override fun saveCallResult(item: ShareParserResult) { - val newShareForFileFromServer = item.shares.map { remoteShare -> - OCShare.fromRemoteShare(remoteShare).also { it.accountOwner = accountName } - } - - localSharesDataSource.insert(newShareForFileFromServer) - } - - override fun shouldFetch(data: List?) = true - - override fun loadFromDb(): LiveData> { - return localSharesDataSource.getSharesForFileAsLiveData( - filePath, accountName, listOf(ShareType.PUBLIC_LINK) - ) - } + ): LiveData> { + val result = MutableLiveData>() + result.postValue(Resource.loading()) - override fun createCall() = remoteSharesDataSource.insertShareForFile( + appExecutors.networkIO().execute() { + // Perform network operation + val remoteOperationResult = remoteSharesDataSource.insertShareForFile( filePath, ShareType.PUBLIC_LINK, "", @@ -116,7 +89,24 @@ class OCShareRepository( expirationTimeInMillis, publicUpload ) - }.asLiveData() + + if (remoteOperationResult.isSuccess) { + val newShareForFileFromServer = remoteOperationResult.data.shares.map { remoteShare -> + OCShare.fromRemoteShare(remoteShare).also { it.accountOwner = accountName } + } + localSharesDataSource.insert(newShareForFileFromServer) + result.postValue(Resource.success()) // Used to close the share creation dialog + } else { + result.postValue( + Resource.error( + remoteOperationResult.code, + msg = remoteOperationResult.httpPhrase, + exception = remoteOperationResult.exception + ) + ) + } + } + return result } override fun updatePublicShareForFile( @@ -126,27 +116,13 @@ class OCShareRepository( expirationDateInMillis: Long, permissions: Int, publicUpload: Boolean - ): LiveData>> { - return object : NetworkBoundResource, ShareParserResult>(appExecutors) { - override fun saveCallResult(item: ShareParserResult) { - val updatedShareForFileFromServer = item.shares.map { remoteShare -> - OCShare.fromRemoteShare(remoteShare).also { it.accountOwner = accountName } - } + ): LiveData> { + val result = MutableLiveData>() + result.postValue(Resource.loading()) - localSharesDataSource.update(updatedShareForFileFromServer.first()) - } - - override fun shouldFetch(data: List?): Boolean { - return true - } - - override fun loadFromDb(): LiveData> { - return localSharesDataSource.getSharesForFileAsLiveData( - filePath, accountName, listOf(ShareType.PUBLIC_LINK) - ) - } - - override fun createCall() = remoteSharesDataSource.updateShareForFile( + appExecutors.networkIO().execute() { + // Perform network operation + val remoteOperationResult = remoteSharesDataSource.updateShareForFile( remoteId, name, password, @@ -154,28 +130,51 @@ class OCShareRepository( permissions, publicUpload ) - }.asLiveData() + + if (remoteOperationResult.isSuccess) { + val updatedShareForFileFromServer = remoteOperationResult.data.shares.map { remoteShare -> + OCShare.fromRemoteShare(remoteShare).also { it.accountOwner = accountName } + } + localSharesDataSource.update(updatedShareForFileFromServer.first()) + result.postValue(Resource.success()) // Used to close the share edition dialog + } else { + result.postValue( + Resource.error( + remoteOperationResult.code, + msg = remoteOperationResult.httpPhrase, + exception = remoteOperationResult.exception + ) + ) + } + } + return result } override fun deletePublicShare( remoteId: Long - ): LiveData>> { - return object : NetworkBoundResource, ShareParserResult>(appExecutors) { - override fun saveCallResult(item: ShareParserResult) { - localSharesDataSource.deleteShare(remoteId) - } + ): LiveData> { + val result = MutableLiveData>() - override fun shouldFetch(data: List?): Boolean { - return true - } + result.postValue(Resource.loading()) + + // Perform network operation + appExecutors.networkIO().execute() { + // Perform network operation + val remoteOperationResult = remoteSharesDataSource.deleteShare(remoteId) - override fun loadFromDb(): LiveData> { - return localSharesDataSource.getSharesForFileAsLiveData( - filePath, accountName, listOf(ShareType.PUBLIC_LINK) + if (remoteOperationResult.isSuccess) { + localSharesDataSource.deleteShare(remoteId) + result.postValue(Resource.success()) // Used to close the share edition dialog + } else { + result.postValue( + Resource.error( + remoteOperationResult.code, + msg = remoteOperationResult.httpPhrase, + exception = remoteOperationResult.exception + ) ) } - - override fun createCall() = remoteSharesDataSource.deleteShare(remoteId) - }.asLiveData() + } + return result } } diff --git a/owncloudApp/src/main/java/com/owncloud/android/shares/repository/ShareRepository.kt b/owncloudApp/src/main/java/com/owncloud/android/shares/repository/ShareRepository.kt index c920d0665a7..16485c15d02 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/shares/repository/ShareRepository.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/shares/repository/ShareRepository.kt @@ -20,16 +20,11 @@ package com.owncloud.android.shares.repository import androidx.lifecycle.LiveData -import com.owncloud.android.lib.resources.shares.ShareType import com.owncloud.android.shares.db.OCShare import com.owncloud.android.vo.Resource interface ShareRepository { - fun loadSharesForFile( - shareTypes: List, - reshares: Boolean, - subfiles: Boolean - ): LiveData>> + fun getSharesForFile(): LiveData>> fun insertPublicShareForFile( permissions: Int, @@ -37,7 +32,7 @@ interface ShareRepository { password: String, expirationTimeInMillis: Long, publicUpload: Boolean - ): LiveData>> + ): LiveData> fun updatePublicShareForFile( remoteId: Long, @@ -46,9 +41,9 @@ interface ShareRepository { expirationDateInMillis: Long, permissions: Int, publicUpload: Boolean - ): LiveData>> + ): LiveData> fun deletePublicShare( remoteId: Long - ): LiveData>> + ): LiveData> } diff --git a/owncloudApp/src/main/java/com/owncloud/android/shares/ui/ShareActivity.kt b/owncloudApp/src/main/java/com/owncloud/android/shares/ui/ShareActivity.kt index 7d25757af1f..951677dead6 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/shares/ui/ShareActivity.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/shares/ui/ShareActivity.kt @@ -30,11 +30,9 @@ import android.os.Bundle import android.util.Log import android.view.MenuItem import androidx.lifecycle.Observer -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.ViewModelProviders import com.google.android.material.snackbar.Snackbar +import com.owncloud.android.MainApp import com.owncloud.android.R -import com.owncloud.android.ViewModelFactory import com.owncloud.android.capabilities.viewmodel.OCCapabilityViewModel import com.owncloud.android.datamodel.OCFile import com.owncloud.android.lib.common.operations.RemoteOperation @@ -53,6 +51,7 @@ import com.owncloud.android.shares.ui.fragment.PublicShareDialogFragment import com.owncloud.android.shares.ui.fragment.ShareFileFragment import com.owncloud.android.shares.ui.fragment.ShareFragmentListener import com.owncloud.android.shares.viewmodel.OCShareViewModel +import com.owncloud.android.testing.OpenForTesting import com.owncloud.android.ui.activity.FileActivity import com.owncloud.android.ui.asynctasks.GetSharesForFileAsyncTask import com.owncloud.android.ui.dialog.RemoveShareDialogFragment @@ -61,10 +60,13 @@ import com.owncloud.android.ui.fragment.EditShareFragment import com.owncloud.android.ui.fragment.SearchShareesFragment import com.owncloud.android.ui.utils.showDialogFragment import com.owncloud.android.vo.Status +import org.koin.androidx.viewmodel.ext.android.viewModel +import org.koin.core.parameter.parametersOf /** * Activity for sharing files */ +@OpenForTesting class ShareActivity : FileActivity(), ShareFragmentListener { private var getSharesForFileAsyncTask: GetSharesForFileAsyncTask? = null @@ -100,23 +102,20 @@ class ShareActivity : FileActivity(), ShareFragmentListener { private val editShareFragment: EditShareFragment? get() = supportFragmentManager.findFragmentByTag(TAG_EDIT_SHARE_FRAGMENT) as EditShareFragment? - private var ocShareViewModelFactory: ViewModelProvider.Factory = ViewModelFactory.build { - OCShareViewModel( + private val ocShareViewModel: OCShareViewModel by viewModel { + parametersOf( file?.remotePath!!, account!!, listOf(ShareType.PUBLIC_LINK) ) } - private var ocCapabilityViewModelFactory: ViewModelProvider.Factory = ViewModelFactory.build { - OCCapabilityViewModel( - account = account!! + private val ocCapabilityViewModel: OCCapabilityViewModel by viewModel { + parametersOf( + account!! ) } - private lateinit var ocShareViewModel: OCShareViewModel - private lateinit var ocCapabilityViewModel: OCCapabilityViewModel - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -129,7 +128,7 @@ class ShareActivity : FileActivity(), ShareFragmentListener { val ft = supportFragmentManager.beginTransaction() - if (savedInstanceState == null) { + if (savedInstanceState == null && file != null && account != null) { // Add Share fragment on first creation val fragment = ShareFileFragment.newInstance(file, account!!) ft.replace( @@ -138,12 +137,6 @@ class ShareActivity : FileActivity(), ShareFragmentListener { ) ft.commit() } - - ocShareViewModel = ViewModelProviders.of(this, ocShareViewModelFactory) - .get(OCShareViewModel::class.java) - - ocCapabilityViewModel = - ViewModelProviders.of(this, ocCapabilityViewModelFactory).get(OCCapabilityViewModel::class.java) } override fun onAccountSet(stateWasRecovered: Boolean) { @@ -267,7 +260,8 @@ class ShareActivity : FileActivity(), ShareFragmentListener { ) Snackbar.make( findViewById(android.R.id.content), - errorMessage, Snackbar.LENGTH_SHORT + errorMessage, + Snackbar.LENGTH_SHORT ).show() shareFileFragment?.updatePublicShares(resource.data as ArrayList) dismissLoadingDialog() @@ -410,6 +404,7 @@ class ShareActivity : FileActivity(), ShareFragmentListener { when (resource?.status) { Status.SUCCESS -> { publicShareFragment?.dismiss() + Log_OC.d("TESTS", "Closing share creation dialog") } Status.ERROR -> { val errorMessage: String = resource.msg ?: ErrorMessageAdapter.getResultMessage( @@ -425,7 +420,10 @@ class ShareActivity : FileActivity(), ShareFragmentListener { showLoadingDialog(R.string.common_loading) } else -> { - Log.d(TAG, "Unknown status when creating public share") + Log.d( + TAG, "Unknown status when creating public share with name ${name} \" +" + + "from account ${account?.name}" + ) } } } @@ -477,7 +475,10 @@ class ShareActivity : FileActivity(), ShareFragmentListener { showLoadingDialog(R.string.common_loading) } else -> { - Log.d(TAG, "Unknown status when updating public share") + Log.d( + TAG, "Unknown status when updating public share with name ${name} " + + "from account ${account?.name}" + ) } } } @@ -498,7 +499,6 @@ class ShareActivity : FileActivity(), ShareFragmentListener { Observer { resource -> when (resource?.status) { Status.SUCCESS -> { - shareFileFragment?.updatePublicShares(resource.data as ArrayList) dismissLoadingDialog() } Status.ERROR -> { @@ -516,7 +516,7 @@ class ShareActivity : FileActivity(), ShareFragmentListener { } else -> { Log.d( - TAG, "Unknown status when removing share ${share.name} " + + TAG, "Unknown status when removing public share with name ${share.name} " + "from account ${account?.name}" ) } @@ -573,10 +573,10 @@ class ShareActivity : FileActivity(), ShareFragmentListener { companion object { private val TAG = ShareActivity::class.java.simpleName - private const val TAG_SHARE_FRAGMENT = "SHARE_FRAGMENT" - private const val TAG_SEARCH_FRAGMENT = "SEARCH_USER_AND_GROUPS_FRAGMENT" - private const val TAG_EDIT_SHARE_FRAGMENT = "EDIT_SHARE_FRAGMENT" - private const val TAG_PUBLIC_SHARE_DIALOG_FRAGMENT = "PUBLIC_SHARE_DIALOG_FRAGMENT" - private const val TAG_REMOVE_SHARE_DIALOG_FRAGMENT = "REMOVE_SHARE_DIALOG_FRAGMENT" + const val TAG_SHARE_FRAGMENT = "SHARE_FRAGMENT" + const val TAG_SEARCH_FRAGMENT = "SEARCH_USER_AND_GROUPS_FRAGMENT" + const val TAG_EDIT_SHARE_FRAGMENT = "EDIT_SHARE_FRAGMENT" + const val TAG_PUBLIC_SHARE_DIALOG_FRAGMENT = "PUBLIC_SHARE_DIALOG_FRAGMENT" + const val TAG_REMOVE_SHARE_DIALOG_FRAGMENT = "REMOVE_SHARE_DIALOG_FRAGMENT" } } diff --git a/owncloudApp/src/main/java/com/owncloud/android/shares/viewmodel/OCShareViewModel.kt b/owncloudApp/src/main/java/com/owncloud/android/shares/viewmodel/OCShareViewModel.kt index e734a6b8caa..9b72bc15c72 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/shares/viewmodel/OCShareViewModel.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/shares/viewmodel/OCShareViewModel.kt @@ -20,9 +20,9 @@ package com.owncloud.android.shares.viewmodel import android.accounts.Account +import android.content.Context import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel -import com.owncloud.android.MainApp import com.owncloud.android.lib.common.OwnCloudAccount import com.owncloud.android.lib.common.OwnCloudClientManagerFactory import com.owncloud.android.lib.resources.shares.ShareType @@ -39,24 +39,28 @@ import com.owncloud.android.vo.Resource */ @OpenForTesting class OCShareViewModel( - val filePath: String, - val account: Account, - val shareTypes: List, - val shareRepository: ShareRepository = OCShareRepository.create( - localSharesDataSource = OCLocalSharesDataSource(), + context: Context, + filePath: String, + account: Account, + shareTypes: List, + val shareRepository: ShareRepository = OCShareRepository( + localSharesDataSource = OCLocalSharesDataSource(context), remoteSharesDataSource = OCRemoteSharesDataSource( OwnCloudClientManagerFactory.getDefaultSingleton().getClientFor( - OwnCloudAccount(account, MainApp.getAppContext()), - MainApp.getAppContext() + OwnCloudAccount(account, context), + context ) ), - filePathToShare = filePath, - accountName = account.name + filePath = filePath, + accountName = account.name, + shareTypes = shareTypes ) ) : ViewModel() { + private val sharesForFile: LiveData>> = shareRepository.getSharesForFile() - fun getSharesForFile(): LiveData>> = - shareRepository.loadSharesForFile(shareTypes, reshares = true, subfiles = false) + fun getSharesForFile(): LiveData>> { + return sharesForFile + } fun insertPublicShareForFile( permissions: Int, @@ -64,7 +68,7 @@ class OCShareViewModel( password: String, expirationTimeInMillis: Long, publicUpload: Boolean - ): LiveData>> = shareRepository.insertPublicShareForFile( + ): LiveData> = shareRepository.insertPublicShareForFile( permissions, name, password, expirationTimeInMillis, publicUpload ) @@ -75,11 +79,11 @@ class OCShareViewModel( expirationDateInMillis: Long, permissions: Int, publicUpload: Boolean - ): LiveData>> = shareRepository.updatePublicShareForFile( + ): LiveData> = shareRepository.updatePublicShareForFile( remoteId, name, password, expirationDateInMillis, permissions, publicUpload ) fun deletePublicShare( remoteId: Long - ): LiveData>> = shareRepository.deletePublicShare(remoteId) + ): LiveData> = shareRepository.deletePublicShare(remoteId) } diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java index e086f1c2d72..9ca526e13c3 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/BaseActivity.java @@ -146,7 +146,7 @@ protected void swapToDefaultAccount() { */ protected void createAccount(boolean mandatoryCreation) { AccountManager am = AccountManager.get(getApplicationContext()); - am.addAccount(MainApp.getAccountType(), + am.addAccount(MainApp.Companion.getAccountType(), null, null, null, @@ -169,7 +169,7 @@ protected void onAccountSet(boolean stateWasRecovered) { } } - protected void setAccount(Account account) { + public void setAccount(Account account) { mCurrentAccount = account; } diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java index bff5f2a317f..5fd00668720 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java @@ -387,7 +387,7 @@ public void setDrawerIndicatorEnabled(boolean enable) { * updates the account list in the drawer. */ private void updateAccountList() { - Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.getAccountType()); + Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.Companion.getAccountType()); if (mNavigationView != null && mDrawerLayout != null) { if (accounts.length > 0) { repopulateAccountList(accounts); @@ -596,7 +596,7 @@ private void toggleAccountList() { private void showMenu() { if (mNavigationView != null) { final int accountCount = AccountManager.get(this) - .getAccountsByType(MainApp.getAccountType()).length; + .getAccountsByType(MainApp.Companion.getAccountType()).length; if (mIsAccountChooserActive) { mAccountChooserToggle.setImageResource(R.drawable.ic_up); @@ -763,7 +763,7 @@ protected void onAccountCreationSuccessful(AccountManagerFuture future) private void populateDrawerOwnCloudAccounts() { mAccountsWithAvatars = new Account[3]; Account[] accountsAll = AccountManager.get(this).getAccountsByType - (MainApp.getAccountType()); + (MainApp.Companion.getAccountType()); Account currentAccount = AccountUtils.getCurrentOwnCloudAccount(this); mAccountsWithAvatars[0] = currentAccount; diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index d33b7fe3b85..81842d642ab 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -107,7 +107,6 @@ import java.util.ArrayList; import java.util.List; -import static com.owncloud.android.MainApp.isBeta; import static com.owncloud.android.db.PreferenceManager.getSortOrder; /** @@ -165,12 +164,10 @@ protected void onCreate(Bundle savedInstanceState) { mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); - if (savedInstanceState != null) { - Log.d(TAG, savedInstanceState.toString()); - } - /// Load of saved instance state if (savedInstanceState != null) { + Log.d(TAG, savedInstanceState.toString()); + mFileWaitingToPreview = savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_PREVIEW); mSyncInProgress = savedInstanceState.getBoolean(KEY_SYNC_IN_PROGRESS); mWaitingToSend = savedInstanceState.getParcelable(FileDisplayActivity.KEY_WAITING_TO_SEND); @@ -224,7 +221,7 @@ protected void onCreate(Bundle savedInstanceState) { Log_OC.v(TAG, "onCreate() end"); - if (getResources().getBoolean(R.bool.enable_rate_me_feature) && !isBeta()) { + if (getResources().getBoolean(R.bool.enable_rate_me_feature) && !MainApp.Companion.isBeta()) { AppRater.appLaunched(this, getPackageName()); } } @@ -653,9 +650,9 @@ private void recoverSortMenuFormPreferences(Menu menu) { private void startSynchronization() { Log_OC.d(TAG, "Got to start sync"); Log_OC.d(TAG, "Requesting sync for " + getAccount().name + " at " + - MainApp.getAuthority() + " with new API"); + MainApp.Companion.getAuthority() + " with new API"); SyncRequest.Builder builder = new SyncRequest.Builder(); - builder.setSyncAdapter(getAccount(), MainApp.getAuthority()); + builder.setSyncAdapter(getAccount(), MainApp.Companion.getAuthority()); builder.setExpedited(true); builder.setManual(true); builder.syncOnce(); @@ -1708,7 +1705,7 @@ public void run() { ); synchFolderOp.execute( getStorageManager(), - MainApp.getAppContext(), + MainApp.Companion.getAppContext(), null, // unneeded, handling via SyncBroadcastReceiver null ); diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java index 025c5aef939..e33064dc959 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ManageAccountsActivity.java @@ -102,7 +102,7 @@ protected void onCreate(Bundle savedInstanceState) { setupToolbar(); updateActionBarTitleAndHomeButtonByString(getResources().getString(R.string.prefs_manage_accounts)); - Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.getAccountType()); + Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.Companion.getAccountType()); mOriginalAccounts = toAccountNameSet(accountList); mOriginalCurrentAccount = AccountUtils.getCurrentOwnCloudAccount(this).name; @@ -158,7 +158,7 @@ public void onBackPressed() { * @return true if aacount list has changed, false if not */ private boolean hasAccountListChanged() { - Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.getAccountType()); + Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.Companion.getAccountType()); Set actualAccounts = toAccountNameSet(accountList); return !mOriginalAccounts.equals(actualAccounts); } @@ -195,7 +195,7 @@ private void initializeComponentGetters() { * @return list of account list items */ private ArrayList getAccountListItems() { - Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.getAccountType()); + Account[] accountList = AccountManager.get(this).getAccountsByType(MainApp.Companion.getAccountType()); ArrayList adapterAccountList = new ArrayList(accountList.length); for (Account account : accountList) { adapterAccountList.add(new AccountListItem(account)); @@ -243,7 +243,7 @@ public void changePasswordOfAccount(Account account) { @Override public void createAccount() { AccountManager am = AccountManager.get(getApplicationContext()); - am.addAccount(MainApp.getAccountType(), + am.addAccount(MainApp.Companion.getAccountType(), null, null, null, @@ -286,8 +286,8 @@ public void run() { @Override public void run(AccountManagerFuture future) { if (future != null && future.isDone()) { - Account account = new Account(mAccountBeingRemoved, MainApp.getAccountType()); - if (!AccountUtils.exists(account.name, MainApp.getAppContext())) { + Account account = new Account(mAccountBeingRemoved, MainApp.Companion.getAccountType()); + if (!AccountUtils.exists(account.name, MainApp.Companion.getAppContext())) { // Cancel transfers of the removed account if (mUploaderBinder != null) { mUploaderBinder.cancel(account); @@ -301,10 +301,10 @@ public void run(AccountManagerFuture future) { mListView.setAdapter(mAccountListAdapter); AccountManager am = AccountManager.get(this); - if (am.getAccountsByType(MainApp.getAccountType()).length == 0) { + if (am.getAccountsByType(MainApp.Companion.getAccountType()).length == 0) { // Show create account screen if there isn't any account am.addAccount( - MainApp.getAccountType(), + MainApp.Companion.getAccountType(), null, null, null, this, null, null @@ -313,7 +313,7 @@ public void run(AccountManagerFuture future) { if (AccountUtils.getCurrentOwnCloudAccount(this) == null) { // current account was removed - set another as current String accountName = ""; - Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.getAccountType()); + Account[] accounts = AccountManager.get(this).getAccountsByType(MainApp.Companion.getAccountType()); if (accounts.length != 0) { accountName = accounts[0].name; } diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/Preferences.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/Preferences.java index 5415df5adbe..52bb48ca819 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/Preferences.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/Preferences.java @@ -469,7 +469,7 @@ public void onCreate(Bundle savedInstanceState) { } boolean loggerEnabled = getResources().getBoolean(R.bool.logger_enabled) || - BuildConfig.DEBUG || MainApp.isBeta(); + BuildConfig.DEBUG || MainApp.Companion.isBeta(); Preference pLogger = findPreference("logger"); if (pLogger != null) { if (loggerEnabled) { diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 5ec112f831e..23dced8dd1a 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -186,7 +186,7 @@ protected void onCreate(Bundle savedInstanceState) { protected void setAccount(Account account, boolean savedAccount) { if (somethingToUpload()) { mAccountManager = (AccountManager) getSystemService(Context.ACCOUNT_SERVICE); - Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAccountType()); + Account[] accounts = mAccountManager.getAccountsByType(MainApp.Companion.getAccountType()); if (accounts.length == 0) { Log_OC.i(TAG, "No ownCloud account is available"); showDialog(DIALOG_NO_ACCOUNT); @@ -260,7 +260,7 @@ public void onClick(DialogInterface dialog, int which) { // Settings.ADD_ACCOUNT_SETTINGS // and Settings.EXTRA_AUTHORITIES Intent intent = new Intent(android.provider.Settings.ACTION_ADD_ACCOUNT); - intent.putExtra("authorities", new String[]{MainApp.getAuthTokenType()}); + intent.putExtra("authorities", new String[]{MainApp.Companion.getAuthTokenType()}); startActivityForResult(intent, REQUEST_CODE__SETUP_ACCOUNT); } else { // since in API7 there is no direct call for @@ -281,7 +281,7 @@ public void onClick(DialogInterface dialog, int which) { }); return builder.create(); case DIALOG_MULTIPLE_ACCOUNT: - Account accounts[] = mAccountManager.getAccountsByType(MainApp.getAccountType()); + Account accounts[] = mAccountManager.getAccountsByType(MainApp.Companion.getAccountType()); CharSequence dialogItems[] = new CharSequence[accounts.length]; OwnCloudAccount oca; for (int i = 0; i < dialogItems.length; ++i) { @@ -303,7 +303,7 @@ public void onClick(DialogInterface dialog, int which) { builder.setItems(dialogItems, new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - setAccount(mAccountManager.getAccountsByType(MainApp.getAccountType())[which]); + setAccount(mAccountManager.getAccountsByType(MainApp.Companion.getAccountType())[which]); onAccountSet(mAccountWasRestored); dialog.dismiss(); mAccountSelected = true; @@ -399,7 +399,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_CANCELED) { finish(); } - Account[] accounts = mAccountManager.getAccountsByType(MainApp.getAuthTokenType()); + Account[] accounts = mAccountManager.getAccountsByType(MainApp.Companion.getAuthTokenType()); if (accounts.length == 0) { showDialog(DIALOG_NO_ACCOUNT); } else { diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/WhatsNewActivity.java b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/WhatsNewActivity.java index 7137f1a2c75..0a0087cef73 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/activity/WhatsNewActivity.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/activity/WhatsNewActivity.java @@ -68,7 +68,7 @@ protected void onCreate(Bundle savedInstanceState) { mProgress = findViewById(R.id.progressIndicator); mPager = findViewById(R.id.contentPanel); - boolean isBeta = MainApp.isBeta(); + boolean isBeta = MainApp.Companion.isBeta(); FeaturesViewAdapter adapter = new FeaturesViewAdapter(getSupportFragmentManager(), FeatureList.getFiltered(getLastSeenVersionCode(), isFirstRun(), isBeta)); @@ -95,7 +95,7 @@ protected void onCreate(Bundle savedInstanceState) { // Wizard already shown SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences.Editor editor = pref.edit(); - editor.putInt(KEY_LAST_SEEN_VERSION_CODE, MainApp.getVersionCode()); + editor.putInt(KEY_LAST_SEEN_VERSION_CODE, MainApp.Companion.getVersionCode()); editor.apply(); } @@ -123,7 +123,7 @@ private void updateNextButtonIfNeeded() { } static private int getLastSeenVersionCode() { - SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(MainApp.getAppContext()); + SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(MainApp.Companion.getAppContext()); return pref.getInt(KEY_LAST_SEEN_VERSION_CODE, 0); } @@ -131,7 +131,7 @@ static private boolean isFirstRun() { if (getLastSeenVersionCode() != 0) { return false; } - return AccountUtils.getCurrentOwnCloudAccount(MainApp.getAppContext()) == null; + return AccountUtils.getCurrentOwnCloudAccount(MainApp.Companion.getAppContext()) == null; } static public void runIfNeeded(Context context) { @@ -145,7 +145,7 @@ static public void runIfNeeded(Context context) { } static private boolean shouldShow(Context context) { - boolean isBeta = MainApp.isBeta(); + boolean isBeta = MainApp.Companion.isBeta(); boolean showWizard = context.getResources().getBoolean(R.bool.wizard_enabled) && !BuildConfig.DEBUG; return showWizard && ((isFirstRun() && context instanceof AccountAuthenticatorActivity) || diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/asynctasks/GetSharesForFileAsyncTask.java b/owncloudApp/src/main/java/com/owncloud/android/ui/asynctasks/GetSharesForFileAsyncTask.java index 4617e283176..248fa5d5f73 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/asynctasks/GetSharesForFileAsyncTask.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/asynctasks/GetSharesForFileAsyncTask.java @@ -66,10 +66,10 @@ protected Pair doInBackground(Object... operation = new GetSharesForFileOperation(file.getRemotePath(), true, false); OwnCloudAccount ocAccount = new OwnCloudAccount( account, - MainApp.getAppContext() + MainApp.Companion.getAppContext() ); OwnCloudClient client = OwnCloudClientManagerFactory.getDefaultSingleton(). - getClientFor(ocAccount, MainApp.getAppContext()); + getClientFor(ocAccount, MainApp.Companion.getAppContext()); result = operation.execute(client, fileDataStorageManager); } catch (Exception e) { diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/dialog/LoginWebViewDialog.java b/owncloudApp/src/main/java/com/owncloud/android/ui/dialog/LoginWebViewDialog.java index 83b3dfc9cf0..aa9efc49676 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/dialog/LoginWebViewDialog.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/dialog/LoginWebViewDialog.java @@ -177,7 +177,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, WebSettings webSettings = mWebView.getSettings(); webSettings.setJavaScriptEnabled(true); webSettings.setSavePassword(false); - webSettings.setUserAgentString(MainApp.getUserAgent()); + webSettings.setUserAgentString(MainApp.Companion.getUserAgent()); webSettings.setSaveFormData(false); // next two settings grant that non-responsive webs are zoomed out when loaded webSettings.setUseWideViewPort(true); diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java b/owncloudApp/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java index 652a44e2225..a3d31a0e1f4 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/fragment/FileDetailFragment.java @@ -470,7 +470,7 @@ private void setFiletype(OCFile file) { } final ThumbnailsCacheManager.AsyncThumbnailDrawable asyncDrawable = new ThumbnailsCacheManager.AsyncThumbnailDrawable( - MainApp.getAppContext().getResources(), + MainApp.Companion.getAppContext().getResources(), thumbnail, task ); diff --git a/owncloudApp/src/main/java/com/owncloud/android/ui/preview/PrepareVideoPlayerAsyncTask.java b/owncloudApp/src/main/java/com/owncloud/android/ui/preview/PrepareVideoPlayerAsyncTask.java index 3ebb2f4dab7..0cf8111c854 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/ui/preview/PrepareVideoPlayerAsyncTask.java +++ b/owncloudApp/src/main/java/com/owncloud/android/ui/preview/PrepareVideoPlayerAsyncTask.java @@ -112,14 +112,14 @@ private HttpDataSource.Factory buildHttpDataSourceFactory( if (file.isDown()) { - return new DefaultHttpDataSourceFactory(MainApp.getUserAgent(), bandwidthMeter); + return new DefaultHttpDataSourceFactory(MainApp.Companion.getUserAgent(), bandwidthMeter); } else { try { OwnCloudCredentials credentials = AccountUtils. - getCredentialsForAccount(MainApp.getAppContext(), account); + getCredentialsForAccount(MainApp.Companion.getAppContext(), account); String login = credentials.getUsername(); String password = credentials.getAuthToken(); @@ -138,7 +138,7 @@ private HttpDataSource.Factory buildHttpDataSourceFactory( params.put("Authorization", auth); } - return new CustomHttpDataSourceFactory(MainApp.getUserAgent(), + return new CustomHttpDataSourceFactory(MainApp.Companion.getUserAgent(), bandwidthMeter, params); } catch (AuthenticatorException e) { diff --git a/owncloudApp/src/main/java/com/owncloud/android/utils/DisplayUtils.java b/owncloudApp/src/main/java/com/owncloud/android/utils/DisplayUtils.java index 117478b903b..67ed183f0da 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/utils/DisplayUtils.java +++ b/owncloudApp/src/main/java/com/owncloud/android/utils/DisplayUtils.java @@ -143,7 +143,7 @@ public static String unixTimeToHumanReadable(long milliseconds) { public static int getSeasonalIconId() { if (Calendar.getInstance().get(Calendar.DAY_OF_YEAR) >= 354 && - MainApp.getAppContext().getString(R.string.app_name).equals(OWNCLOUD_APP_NAME)) { + MainApp.Companion.getAppContext().getString(R.string.app_name).equals(OWNCLOUD_APP_NAME)) { return R.drawable.winter_holidays_icon; } else { return R.mipmap.icon; diff --git a/owncloudApp/src/main/java/com/owncloud/android/utils/FileStorageUtils.java b/owncloudApp/src/main/java/com/owncloud/android/utils/FileStorageUtils.java index 2a34467347c..7bff405e441 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/utils/FileStorageUtils.java +++ b/owncloudApp/src/main/java/com/owncloud/android/utils/FileStorageUtils.java @@ -66,7 +66,7 @@ public class FileStorageUtils { */ public static String getDataFolder() { File sdCard = Environment.getExternalStorageDirectory(); - return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder(); + return sdCard.getAbsolutePath() + "/" + MainApp.Companion.getDataFolder(); } /** @@ -74,7 +74,7 @@ public static String getDataFolder() { */ public static String getSavePath(String accountName) { File sdCard = Environment.getExternalStorageDirectory(); - return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/" + Uri.encode(accountName, "@"); + return sdCard.getAbsolutePath() + "/" + MainApp.Companion.getDataFolder() + "/" + Uri.encode(accountName, "@"); // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, // that can be in the accountName since 0.1.190B } @@ -93,7 +93,7 @@ public static String getDefaultSavePathFor(String accountName, OCFile file) { */ public static String getTemporalPath(String accountName) { File sdCard = Environment.getExternalStorageDirectory(); - return sdCard.getAbsolutePath() + "/" + MainApp.getDataFolder() + "/tmp/" + Uri.encode(accountName, "@"); + return sdCard.getAbsolutePath() + "/" + MainApp.Companion.getDataFolder() + "/tmp/" + Uri.encode(accountName, "@"); // URL encoding is an 'easy fix' to overcome that NTFS and FAT32 don't allow ":" in file names, // that can be in the accountName since 0.1.190B } @@ -118,7 +118,7 @@ public static long getUsableSpace(String accountName) { } public static String getLogPath() { - return Environment.getExternalStorageDirectory() + File.separator + MainApp.getDataFolder() + File.separator + "log"; + return Environment.getExternalStorageDirectory() + File.separator + MainApp.Companion.getDataFolder() + File.separator + "log"; } /** diff --git a/owncloudApp/src/main/java/com/owncloud/android/vo/Resource.kt b/owncloudApp/src/main/java/com/owncloud/android/vo/Resource.kt index 1a5a663d6d3..cde82583448 100644 --- a/owncloudApp/src/main/java/com/owncloud/android/vo/Resource.kt +++ b/owncloudApp/src/main/java/com/owncloud/android/vo/Resource.kt @@ -16,9 +16,10 @@ package com.owncloud.android.vo -import com.owncloud.android.vo.Status.* import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode -import java.lang.Exception +import com.owncloud.android.vo.Status.ERROR +import com.owncloud.android.vo.Status.LOADING +import com.owncloud.android.vo.Status.SUCCESS /** * A generic class that holds a value with its loading status. @@ -32,7 +33,7 @@ data class Resource( val exception: Exception? = null ) { companion object { - fun success(data: T?): Resource { + fun success(data: T? = null): Resource { return Resource(SUCCESS, ResultCode.OK, data) } @@ -45,7 +46,7 @@ data class Resource( return Resource(ERROR, code, data, msg, exception) } - fun loading(data: T?): Resource { + fun loading(data: T? = null): Resource { return Resource(LOADING, data = data) } } diff --git a/owncloudApp/src/test-common/java/com/owncloud/android/utils/TestUtil.kt b/owncloudApp/src/test-common/java/com/owncloud/android/utils/TestUtil.kt index afaabca8417..07e8ad284e5 100644 --- a/owncloudApp/src/test-common/java/com/owncloud/android/utils/TestUtil.kt +++ b/owncloudApp/src/test-common/java/com/owncloud/android/utils/TestUtil.kt @@ -76,6 +76,7 @@ object TestUtil { path: String, expirationDate: Long = 1000, isFolder: Boolean, + permissions: Int = 1, remoteId: Long = 1, accountOwner: String = "admin@server", name: String, @@ -84,6 +85,7 @@ object TestUtil { shareWith = shareWith, shareType = 3, path = path, + permissions = permissions, expirationDate = expirationDate, isFolder = isFolder, remoteId = remoteId, diff --git a/owncloudApp/src/test/java/com/owncloud/android/NetworkBoundResourceTest.kt b/owncloudApp/src/test/java/com/owncloud/android/NetworkBoundResourceTest.kt index b30e08dd8be..e3388dbb1f2 100644 --- a/owncloudApp/src/test/java/com/owncloud/android/NetworkBoundResourceTest.kt +++ b/owncloudApp/src/test/java/com/owncloud/android/NetworkBoundResourceTest.kt @@ -78,7 +78,7 @@ class NetworkBoundResourceTest { dbData.value = fetchedDbValue } - override fun shouldFetch(data: List?) = true + override fun shouldFetchFromNetwork(data: List?) = true override fun loadFromDb(): LiveData> = dbData @@ -128,7 +128,7 @@ class NetworkBoundResourceTest { saved.set(true) } - override fun shouldFetch(data: List?) = true + override fun shouldFetchFromNetwork(data: List?) = true override fun loadFromDb(): LiveData> = dbData.apply { value = fetchedDbValue } @@ -170,7 +170,7 @@ class NetworkBoundResourceTest { saved.set(true) } - override fun shouldFetch(data: List?) = true + override fun shouldFetchFromNetwork(data: List?) = true override fun loadFromDb(): LiveData> = dbData diff --git a/owncloudApp/src/test/java/com/owncloud/android/shares/repository/OCShareRepositoryTest.kt b/owncloudApp/src/test/java/com/owncloud/android/shares/repository/OCShareRepositoryTest.kt index fdeea1d9d74..f6aaacaa84f 100644 --- a/owncloudApp/src/test/java/com/owncloud/android/shares/repository/OCShareRepositoryTest.kt +++ b/owncloudApp/src/test/java/com/owncloud/android/shares/repository/OCShareRepositoryTest.kt @@ -189,12 +189,11 @@ class OCShareRepositoryTest { ) val data = insertShare(localData, remoteOperationResult) - val observer = mock>>>() + val observer = mock>>() data.observeForever(observer) - // Get public shares from database to observe them, is called twice (one showing current db shares while - // creating share on server and another one with db shares already updated with just created share) - verify(localSharesDataSource, times(2)).getSharesForFileAsLiveData( + // Get public shares from database is called once, when creating the repository + verify(localSharesDataSource, times(1)).getSharesForFileAsLiveData( "/Photos/", "admin@server", listOf(ShareType.PUBLIC_LINK) ) @@ -232,12 +231,12 @@ class OCShareRepositoryTest { // Retrieving public shares from server... // Observe changes in database livedata when there's an error from server - val observer = mock>>>() + val observer = mock>>() data.observeForever(observer) verify(observer).onChanged( Resource.error( - RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, localData.value, exception = exception + RemoteOperationResult.ResultCode.SHARE_NOT_FOUND, exception = exception ) ) } @@ -253,12 +252,11 @@ class OCShareRepositoryTest { val data = updateShare(localData, remoteOperationResult) - val observer = mock>>>() + val observer = mock>>() data.observeForever(observer) - // Get public shares from database to observe them, is called twice (one showing current db shares while - // updating share on server and another one with db shares already updated with just updated share) - verify(localSharesDataSource, times(2)).getSharesForFileAsLiveData( + // Get public shares from database is called once, when creating the repository + verify(localSharesDataSource, times(1)).getSharesForFileAsLiveData( "/Photos/", "admin@server", listOf(ShareType.PUBLIC_LINK) ) @@ -281,12 +279,11 @@ class OCShareRepositoryTest { val data = deleteShare(localData, remoteOperationResult) - val observer = mock>>>() + val observer = mock>>() data.observeForever(observer) - // Get public shares from database to observe them, is called twice (one showing current db shares while - // deleting share on server and another one with db shares already updated with just deleted share) - verify(localSharesDataSource, times(2)).getSharesForFileAsLiveData( + // Get public shares from database is called once, when creating the repository + verify(localSharesDataSource, times(1)).getSharesForFileAsLiveData( "/Photos/", "admin@server", listOf(ShareType.PUBLIC_LINK) ) @@ -310,12 +307,13 @@ class OCShareRepositoryTest { val remoteSharesDataSource = RemoteSharesDataSourceTest(remoteOperationResult) - return OCShareRepository.create( + return OCShareRepository( InstantAppExecutors(), localSharesDataSource, remoteSharesDataSource, "/Photos/", - "admin@server" + "admin@server", + listOf(ShareType.PUBLIC_LINK) ) } @@ -325,15 +323,13 @@ class OCShareRepositoryTest { ): LiveData>> { val ocShareRepository = createRepositoryWithData(localData, remoteOperationResult) - return ocShareRepository.loadSharesForFile( - listOf(ShareType.PUBLIC_LINK), reshares = true, subfiles = false - ) + return ocShareRepository.getSharesForFile() } private fun insertShare( localData: MutableLiveData>, remoteOperationResult: RemoteOperationResult - ): LiveData>> { + ): LiveData> { val ocShareRepository = createRepositoryWithData(localData, remoteOperationResult) return ocShareRepository.insertPublicShareForFile( @@ -348,7 +344,7 @@ class OCShareRepositoryTest { private fun updateShare( localData: MutableLiveData>, remoteOperationResult: RemoteOperationResult - ): LiveData>> { + ): LiveData> { val ocShareRepository = createRepositoryWithData(localData, remoteOperationResult) return ocShareRepository.updatePublicShareForFile( @@ -364,9 +360,8 @@ class OCShareRepositoryTest { private fun deleteShare( localData: MutableLiveData>, remoteOperationResult: RemoteOperationResult - ): LiveData>> { + ): LiveData> { val ocShareRepository = createRepositoryWithData(localData, remoteOperationResult) - return ocShareRepository.deletePublicShare( 1 )