diff --git a/.gitignore b/.gitignore index 3f4fefdb58cd598656922125e157f27fb1cb1a9c..2ca193d01231f71851fed9e47216071e80f4e03a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /build /captures .externalNativeBuild +/iotivity-base-release/*.aar diff --git a/build.gradle b/build.gradle index 1aef4ddcff72af1737cbeb0897c30bb0f46376fd..eb23364c5de2555070e406ad4a94fd90febfe05f 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0' + classpath 'com.android.tools.build:gradle:3.2.1' // NOTE: Do not place your application dependencies here; they belong diff --git a/gradle.properties b/gradle.properties index aac7c9b4614ccfde6c721f24994cf30885a791d0..e4c1a659d9934604460aaa909e42e30ab53953de 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,3 +15,7 @@ org.gradle.jvmargs=-Xmx1536m # This option should only be used with decoupled projects. More details, visit # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true + +# Android X: https://developer.android.com/topic/libraries/support-library/androidx-rn +android.enableJetifier=true +android.useAndroidX=true diff --git a/otgc/build.gradle b/otgc/build.gradle index a5b9ee11fcb0bcc35b93bdf4e6475dcfb71a6e71..698520b559bc74fe89881274d4cba01609f0e783 100644 --- a/otgc/build.gradle +++ b/otgc/build.gradle @@ -2,29 +2,36 @@ apply plugin: 'com.android.application' apply plugin: 'jacoco' project.ext { - supportLibraryVersion = "27.1.1" - daggerVersion = "2.15" - butterKnifeVersion = "8.8.1" + appCompatVersion = "1.0.2" + supportLibraryVersion = "1.0.0" + constraintLayoutVersion = "1.1.3" + materialVersion = "1.1.0-alpha01" + lifecycleVersion = "2.0.0" + roomVersion = "2.0.0" + daggerVersion = "2.17" + butterKnifeVersion = "9.0.0-rc2" rxJavaVersion = "2.1.0" rxAndroidVersion = "2.0.1" - lifecycleVersion = "1.1.1" timberVersion = "4.7.0" - roomVersion = "1.1.1" swaggerParserVersion = "1.0.38" gsonVersion = "2.8.0" cborVersion = "3.3.0" spongyCastleVersion = "1.58.0.0" + junitVersion = "4.12" + mockitoVersion = "1.10.19" + testRunnerVersion = "1.1.1-alpha01" + espressoVersion = "3.1.1-alpha01" } android { - compileSdkVersion 27 + compileSdkVersion 28 defaultConfig { applicationId "org.openconnectivity.otgc" minSdkVersion 21 - targetSdkVersion 27 + targetSdkVersion 28 versionCode 13 - versionName "1.2.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + versionName "1.3.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -45,61 +52,56 @@ android { } dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation "com.android.support:appcompat-v7:$project.supportLibraryVersion" - implementation "com.android.support:design:$project.supportLibraryVersion" - implementation "com.android.support:cardview-v7:$project.supportLibraryVersion" - implementation "com.android.support:support-v4:$project.supportLibraryVersion" - - // Dagger core + // local modules + implementation project(':iotivity-base-release') + implementation project(':easy-setup-core') + // AndroidX: Support Library + implementation "androidx.appcompat:appcompat:$project.appCompatVersion" + implementation "androidx.recyclerview:recyclerview:$project.supportLibraryVersion" + implementation "androidx.recyclerview:recyclerview-selection:$project.supportLibraryVersion" + implementation "androidx.cardview:cardview:$project.supportLibraryVersion" + implementation "androidx.legacy:legacy-support-v4:$project.supportLibraryVersion" + // AndroidX: ConstraintLayout + implementation "androidx.constraintlayout:constraintlayout:$project.constraintLayoutVersion" + // Material Components + implementation "com.google.android.material:material:$project.materialVersion" + // AndroidX: Lifecycle + implementation "androidx.lifecycle:lifecycle-runtime:$project.lifecycleVersion" + implementation "androidx.lifecycle:lifecycle-extensions:$project.lifecycleVersion" + annotationProcessor "androidx.lifecycle:lifecycle-compiler:$project.lifecycleVersion" + // AndroidX: Room + implementation "androidx.room:room-runtime:$project.roomVersion" + implementation "androidx.room:room-rxjava2:$project.roomVersion" + annotationProcessor "androidx.room:room-compiler:$project.roomVersion" + // Dagger implementation "com.google.dagger:dagger:$project.daggerVersion" annotationProcessor "com.google.dagger:dagger-compiler:$project.daggerVersion" - - // Dagger Android implementation "com.google.dagger:dagger-android:$project.daggerVersion" implementation "com.google.dagger:dagger-android-support:$project.daggerVersion" annotationProcessor "com.google.dagger:dagger-android-processor:$project.daggerVersion" - // ButterKnife implementation "com.jakewharton:butterknife:$project.butterKnifeVersion" annotationProcessor "com.jakewharton:butterknife-compiler:$project.butterKnifeVersion" - // ReactiveX implementation "io.reactivex.rxjava2:rxjava:$project.rxJavaVersion" implementation "io.reactivex.rxjava2:rxandroid:$project.rxAndroidVersion" - // Timber implementation "com.jakewharton.timber:timber:$project.timberVersion" - - // Lifecycle - implementation "android.arch.lifecycle:runtime:$project.lifecycleVersion" - implementation "android.arch.lifecycle:extensions:$project.lifecycleVersion" - annotationProcessor "android.arch.lifecycle:compiler:$project.lifecycleVersion" - // Swagger implementation "io.swagger:swagger-parser:$project.swaggerParserVersion" - - // Room - implementation "android.arch.persistence.room:runtime:$project.roomVersion" - implementation "android.arch.persistence.room:rxjava2:$project.roomVersion" - annotationProcessor "android.arch.persistence.room:compiler:$project.roomVersion" - // Gson implementation "com.google.code.gson:gson:$project.gsonVersion" - // CBOR implementation "com.upokecenter:cbor:$project.cborVersion" - - // Bouncy Castle Provider + // Spongy Castle implementation "com.madgag.spongycastle:core:$project.spongyCastleVersion" implementation "com.madgag.spongycastle:prov:$project.spongyCastleVersion" implementation "com.madgag.spongycastle:bcpkix-jdk15on:$project.spongyCastleVersion" - - implementation 'com.android.support.constraint:constraint-layout:1.1.2' - testImplementation 'junit:junit:4.12' - testImplementation 'org.mockito:mockito-core:1.10.19' - androidTestImplementation 'com.android.support.test:runner:1.0.2' - androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - implementation project(':iotivity-base-release') - implementation project(':easy-setup-core') + // JUnit + testImplementation "junit:junit:$project.junitVersion" + // Mockito + testImplementation "org.mockito:mockito-core:$project.mockitoVersion" + // AndroidX: Test + androidTestImplementation "androidx.test:runner:$project.testRunnerVersion" + androidTestImplementation "androidx.test.espresso:espresso-core:$project.espressoVersion" } diff --git a/otgc/src/androidTest/java/org/openconnectivity/otgc/accesscontrol/data/repository/AmsRepositoryTest.java b/otgc/src/androidTest/java/org/openconnectivity/otgc/accesscontrol/data/repository/AmsRepositoryTest.java index 9c10d003ebb88f0308688c9893171b51dcacf873..cd83baecea5c8facbd5df2272c42d2f4bf384651 100644 --- a/otgc/src/androidTest/java/org/openconnectivity/otgc/accesscontrol/data/repository/AmsRepositoryTest.java +++ b/otgc/src/androidTest/java/org/openconnectivity/otgc/accesscontrol/data/repository/AmsRepositoryTest.java @@ -22,7 +22,7 @@ package org.openconnectivity.otgc.accesscontrol.data.repository; -import android.support.test.InstrumentationRegistry; +import androidx.test.InstrumentationRegistry; import org.iotivity.base.AceSubjectType; import org.iotivity.base.OcException; diff --git a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/persistence/UserDaoTest.java b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/persistence/UserDaoTest.java index 3d10a98c1f6d4e9102ab6b6eeb59529e21b1608d..bc4eed694b628fdcb6febf29cd9331dc796b40fd 100644 --- a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/persistence/UserDaoTest.java +++ b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/persistence/UserDaoTest.java @@ -22,10 +22,10 @@ package org.openconnectivity.otgc.common.data.persistence; -import android.arch.persistence.room.EmptyResultSetException; -import android.arch.persistence.room.Room; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.room.EmptyResultSetException; +import androidx.room.Room; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Before; diff --git a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/IORepositoryTest.java b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/IORepositoryTest.java index 2a0ebe5578c916ffc2397116865cb13929de7244..ac525d64ac746e825d5fe150bcb2b3cf3b00746a 100644 --- a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/IORepositoryTest.java +++ b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/IORepositoryTest.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.common.data.repository; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.junit.Before; import org.junit.Test; diff --git a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/PlatformRepositoryTest.java b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/PlatformRepositoryTest.java index 8352a81d5e78df3d4b9fc975a4612a1408c961e4..96629af115355d12dab4d7fe7dc11807ef308ac5 100644 --- a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/PlatformRepositoryTest.java +++ b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/PlatformRepositoryTest.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.common.data.repository; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.iotivity.base.OcException; import org.junit.Before; diff --git a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/ProvisioningRepositoryTest.java b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/ProvisioningRepositoryTest.java index 05e5fef33e309a67592f4a08d082794f788fef60..f647c59028bcd8706cc3aa1b5a39afe1e0645620 100644 --- a/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/ProvisioningRepositoryTest.java +++ b/otgc/src/androidTest/java/org/openconnectivity/otgc/common/data/repository/ProvisioningRepositoryTest.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.common.data.repository; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import org.junit.After; import org.junit.Before; diff --git a/otgc/src/main/AndroidManifest.xml b/otgc/src/main/AndroidManifest.xml index fc1466187b65e87e0da12b428cf2bf31c97296a4..04cfef10b92e6985ea626f93606c571586d0321a 100644 --- a/otgc/src/main/AndroidManifest.xml +++ b/otgc/src/main/AndroidManifest.xml @@ -69,6 +69,11 @@ android:name=".client.presentation.view.GenericClientActivity" android:configChanges="orientation|screenSize" android:parentActivityName=".devicelist.presentation.view.DeviceListActivity" /> + > execute(String deviceId) { return iotivityRepository.getDeviceCoapIpv6Host(deviceId) - .flatMap(iotivityRepository::findResource) + .flatMap(iotivityRepository::findResources) .map(ocResources -> { List verticalResources = new ArrayList<>(); for (OcResource ocResource : ocResources) { diff --git a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlActivity.java index ebb323e2b3c90a75b1bdd34356364572630fb1b4..4011665f95f6ef4778d8069642db3e68eba8fc43 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlActivity.java @@ -22,17 +22,17 @@ package org.openconnectivity.otgc.accesscontrol.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; import android.view.View; import android.widget.ProgressBar; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlAdapter.java b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlAdapter.java index 681d39665daa8352f29e46856d3cd6881f93a394..7dc81d851214d2080c819491097aec57ae583cd5 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlAdapter.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AccessControlAdapter.java @@ -23,9 +23,9 @@ package org.openconnectivity.otgc.accesscontrol.presentation.view; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.util.SortedList; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.SortedList; +import androidx.recyclerview.widget.RecyclerView; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.View; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AceActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AceActivity.java index 083bf425bb2a5e21f5a0ff458328e12b5e362eec..e1f0d8fbe5c969a33c4e92c2494ade1a2d853c9b 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AceActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/view/AceActivity.java @@ -22,14 +22,14 @@ package org.openconnectivity.otgc.accesscontrol.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.util.SparseBooleanArray; import android.view.MenuItem; import android.view.View; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AccessControlViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AccessControlViewModel.java index 7b6556ae3b72ae961afcbeadcf83dbfec12ab8a3..0a17342b8af4e77b345cdcce7c7786c2640e88fe 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AccessControlViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AccessControlViewModel.java @@ -22,9 +22,9 @@ package org.openconnectivity.otgc.accesscontrol.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; import org.iotivity.base.OicSecAce; import org.openconnectivity.otgc.accesscontrol.domain.usecase.DeleteAclUseCase; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AceViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AceViewModel.java index a55027606158d44bd56a3abdefbc6797d6a27dc6..105d18c643f72d88ffb36ce53069ffd350ae855d 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AceViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/accesscontrol/presentation/viewmodel/AceViewModel.java @@ -22,15 +22,13 @@ package org.openconnectivity.otgc.accesscontrol.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; import org.openconnectivity.otgc.accesscontrol.domain.usecase.CreateAclUseCase; import org.openconnectivity.otgc.accesscontrol.domain.usecase.RetrieveVerticalResourcesUseCase; import org.openconnectivity.otgc.accesscontrol.domain.usecase.UpdateAclUseCase; -import org.openconnectivity.otgc.client.domain.model.SerializableResource; -import org.openconnectivity.otgc.client.domain.usecase.GetResourcesUseCase; import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelError; import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelErrorType; import org.openconnectivity.otgc.common.domain.rx.SchedulersFacade; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/data/repository/ResourceRepository.java b/otgc/src/main/java/org/openconnectivity/otgc/client/data/repository/ResourceRepository.java index 66bb2ca6b8c82311347c7367f120c7068e95988e..dfa1062d67240728f16037a9bc485f8d9baa301c 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/data/repository/ResourceRepository.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/data/repository/ResourceRepository.java @@ -32,10 +32,14 @@ import org.iotivity.base.OcException; import org.iotivity.base.OcHeaderOption; import org.iotivity.base.OcRepresentation; import org.iotivity.base.OcResource; +import org.iotivity.base.OicSecResr; import org.iotivity.base.QualityOfService; +import org.openconnectivity.otgc.common.constant.OcfResourceType; import javax.inject.Inject; import javax.inject.Singleton; + +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -103,6 +107,26 @@ public class ResourceRepository { emitter.onComplete(); }); } + + public List getVerticalResources(List ocResources) { + List resources = new ArrayList<>(); + for (OcResource resource : ocResources) { + for (String resourceType : resource.getResourceTypes()) { + if (OcfResourceType.isVerticalResourceType(resourceType)) { + OicSecResr res = new OicSecResr(); + res.setHref(resource.getUri()); + List types = resource.getResourceTypes(); + res.setTypes(types); + res.setTypeLen(types.size()); + List interfaces = resource.getResourceInterfaces(); + res.setInterfaces(interfaces); + res.setInterfaceLen(interfaces.size()); + resources.add(res); + } + } + } + return resources; + } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/domain/model/SerializableResource.java b/otgc/src/main/java/org/openconnectivity/otgc/client/domain/model/SerializableResource.java index f5f35b795bdea6c34e1322c00b96d6348dd00532..2a8e9fa66ec7e7e9302985d153d3232513c6eb8e 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/domain/model/SerializableResource.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/domain/model/SerializableResource.java @@ -22,7 +22,7 @@ package org.openconnectivity.otgc.client.domain.model; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.iotivity.base.OcResource; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/domain/usecase/UiFromSwaggerUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/client/domain/usecase/UiFromSwaggerUseCase.java index a5a283e250a5aae6d22aa23620dcd49eb9535d35..eb63f3b7dd22bb5c759c2fc999f5d18cf1f646d7 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/domain/usecase/UiFromSwaggerUseCase.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/domain/usecase/UiFromSwaggerUseCase.java @@ -23,7 +23,7 @@ package org.openconnectivity.otgc.client.domain.usecase; import android.os.Build; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.json.JSONArray; import org.json.JSONException; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/DeviceInfoAdapter.java b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/DeviceInfoAdapter.java index 17107289f1b6715a3f01dc6b320e6b71079469da..eed4eacb20875cba931c9ea7fc29f105f9e4b449 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/DeviceInfoAdapter.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/DeviceInfoAdapter.java @@ -23,8 +23,8 @@ package org.openconnectivity.otgc.client.presentation.view; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/GenericClientActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/GenericClientActivity.java index 47875aee611a219936b326e3cc5377066e5d85cb..c3c925cbfb8cbb7cec8821427dca7e94c30ce662 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/GenericClientActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/GenericClientActivity.java @@ -21,20 +21,20 @@ */ package org.openconnectivity.otgc.client.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.DividerItemDecoration; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentTransaction; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.appcompat.widget.Toolbar; import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/IntrospectedFragment.java b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/IntrospectedFragment.java index e083f0664518e79cd2d18bd1d8ceb8e07317aeb9..2e9436853467864150fb16a064b872a9008e8baa 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/IntrospectedFragment.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/IntrospectedFragment.java @@ -22,12 +22,12 @@ package org.openconnectivity.otgc.client.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.content.ContextCompat; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.core.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/ResourceFragment.java b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/ResourceFragment.java index 2e2189161ec875c7de3e77d3d781942329dbad43..a5529ed4f33e4bbbbbc71327164a444d060e5826 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/ResourceFragment.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/view/ResourceFragment.java @@ -22,22 +22,23 @@ package org.openconnectivity.otgc.client.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; + import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.content.ContextCompat; -import android.text.Editable; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.core.content.ContextCompat; import android.text.InputType; -import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.GridLayout; import android.widget.ImageButton; import android.widget.LinearLayout; +import android.widget.Spinner; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; @@ -53,6 +54,7 @@ import org.openconnectivity.otgc.di.Injectable; import java.text.DecimalFormat; import java.text.NumberFormat; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -211,6 +213,41 @@ public class ResourceFragment extends Fragment implements Injectable { } else { ((TextView) mViews.get(entry.getKey())).setText(numberFormat.format(entry.getValue())); } + } else if (entry.getValue() instanceof String) { + if (isViewEnabled(response.getResourceInterfaces())) { + ((EditText) mViews.get(entry.getKey())).setText(entry.getValue().toString()); + } else { + ((TextView) mViews.get(entry.getKey())).setText(entry.getValue().toString()); + } + } else if (entry.getValue() instanceof String[]) { + List list = Arrays.asList((String[]) entry.getValue()); + ArrayAdapter dataAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, list); + dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + ((Spinner) mViews.get(entry.getKey())).setAdapter(dataAdapter); + } else if (entry.getValue() instanceof int[]) { + LinearLayout layout = ((LinearLayout)mViews.get(entry.getKey())); + NumberFormat numberFormat = NumberFormat.getInstance(); + int i = 0; + for (int value : (int[])entry.getValue()) { + if (isViewEnabled(response.getResourceInterfaces())) { + ((EditText)layout.getChildAt(i)).setText(numberFormat.format(value)); + } else { + ((TextView)layout.getChildAt(i)).setText(numberFormat.format(value)); + } + i++; + } + } else if (entry.getValue() instanceof double[]) { + LinearLayout layout = ((LinearLayout)mViews.get(entry.getKey())); + NumberFormat numberFormat = new DecimalFormat("0.0"); + int i = 0; + for (double value : (double[])entry.getValue()) { + if (isViewEnabled(response.getResourceInterfaces())) { + ((EditText)layout.getChildAt(i)).setText(numberFormat.format(value)); + } else { + ((TextView)layout.getChildAt(i)).setText(numberFormat.format(value)); + } + i++; + } } } else { View view = null; @@ -240,24 +277,12 @@ public class ResourceFragment extends Fragment implements Injectable { et.setInputType(InputType.TYPE_CLASS_NUMBER); NumberFormat numberFormat = NumberFormat.getInstance(); et.setText(numberFormat.format(entry.getValue())); - et.addTextChangedListener(new TextWatcher() { - - @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) { - - } - - @Override - public void onTextChanged(CharSequence s, int start, int before, int count) { - - } - - @Override - public void afterTextChanged(Editable s) { + et.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { Integer number; try { - number = Integer.valueOf(s.toString()); + number = Integer.valueOf(et.getText().toString()); } catch (NumberFormatException e) { return; } @@ -287,6 +312,26 @@ public class ResourceFragment extends Fragment implements Injectable { et.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL); NumberFormat numberFormat = new DecimalFormat("0.0"); et.setText(numberFormat.format(entry.getValue())); + et.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + Double number; + + try { + number = Double.valueOf(et.getText().toString()); + } catch (NumberFormatException e) { + return; + } + + OcRepresentation rep = new OcRepresentation(); + try { + rep.setValue(entry.getKey(), number); + } catch (OcException e) { + return; + } + mViewModel.postRequest(mDeviceId, mResource.getUri(), mResource.getResourceTypes(), mResource.getResourceInterfaces(), + rep); + } + }); view = et; } else { @@ -296,6 +341,131 @@ public class ResourceFragment extends Fragment implements Injectable { view = tv; } + } else if (entry.getValue() instanceof String) { + if (isViewEnabled(response.getResourceInterfaces())) { + EditText et = new EditText(getContext()); + et.setInputType(InputType.TYPE_CLASS_TEXT); + et.setText(String.valueOf(entry.getValue())); + et.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + OcRepresentation rep = new OcRepresentation(); + try { + rep.setValue(entry.getKey(), et.getText().toString()); + } catch (OcException e) { + return; + } + mViewModel.postRequest(mDeviceId, mResource.getUri(), mResource.getResourceTypes(), mResource.getResourceInterfaces(), + rep); + } + }); + + view = et; + } else { + TextView tv = new TextView(getContext()); + tv.setText(String.valueOf(entry.getValue())); + + view = tv; + } + } else if (entry.getValue() instanceof String[]) { + List list = Arrays.asList((String[]) entry.getValue()); + ArrayAdapter dataAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_item, list); + dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + + // attaching data adapter to list view + Spinner spinner = new Spinner(getContext()); + spinner.setAdapter(dataAdapter); + + view = spinner; + } else if (entry.getValue() instanceof int[]) { + LinearLayout layout = new LinearLayout(getContext()); + layout.setOrientation(LinearLayout.HORIZONTAL); + for (int value : (int[]) entry.getValue()) { + if (isViewEnabled(response.getResourceInterfaces())) { + EditText et = new EditText(getContext()); + et.setInputType(InputType.TYPE_CLASS_NUMBER); + NumberFormat numberFormat = NumberFormat.getInstance(); + et.setText(numberFormat.format(value)); + et.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + int[] ret = new int[layout.getChildCount()]; + for (int i = 0; i < layout.getChildCount(); i++) { + EditText tmp = (EditText) layout.getChildAt(i); + Integer number; + try { + number = Integer.valueOf(tmp.getText().toString()); + } catch (NumberFormatException e) { + return; + } + ret[i] = number; + } + + OcRepresentation rep = new OcRepresentation(); + try { + rep.setValue(entry.getKey(), ret); + } catch (OcException e) { + return; + } + mViewModel.postRequest(mDeviceId, mResource.getUri(), mResource.getResourceTypes(), mResource.getResourceInterfaces(), + rep); + } + }); + + layout.addView(et); + } else { + TextView tv = new TextView(getContext()); + NumberFormat numberFormat = NumberFormat.getInstance(); + tv.setText(numberFormat.format(value)); + + layout.addView(tv); + } + } + + view = layout; + } else if (entry.getValue() instanceof double[]) { + LinearLayout layout = new LinearLayout(getContext()); + layout.setOrientation(LinearLayout.HORIZONTAL); + for (double value : (double[]) entry.getValue()) { + if (isViewEnabled(response.getResourceInterfaces())) { + EditText et = new EditText(getContext()); + et.setInputType(InputType.TYPE_CLASS_NUMBER); + NumberFormat numberFormat = NumberFormat.getInstance(); + et.setText(numberFormat.format(value)); + et.setOnFocusChangeListener((v, hasFocus) -> { + if (!hasFocus) { + double[] ret = new double[layout.getChildCount()]; + for (int i = 0; i < layout.getChildCount(); i++) { + EditText tmp = (EditText) layout.getChildAt(i); + Double number; + try { + number = Double.valueOf(tmp.getText().toString()); + } catch (NumberFormatException e) { + return; + } + ret[i] = number; + } + + OcRepresentation rep = new OcRepresentation(); + try { + rep.setValue(entry.getKey(), ret); + } catch (OcException e) { + return; + } + mViewModel.postRequest(mDeviceId, mResource.getUri(), mResource.getResourceTypes(), mResource.getResourceInterfaces(), + rep); + } + }); + + layout.addView(et); + } else { + TextView tv = new TextView(getContext()); + NumberFormat numberFormat = NumberFormat.getInstance(); + tv.setText(numberFormat.format(value)); + + layout.addView(tv); + } + } + + view = layout; } if (view != null) { diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/GenericClientViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/GenericClientViewModel.java index 09e3178786948941db137417aa1d8f89210acf58..f83be8a743d4866aeff891057086fe1b5978b7eb 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/GenericClientViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/GenericClientViewModel.java @@ -21,8 +21,8 @@ */ package org.openconnectivity.otgc.client.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import org.openconnectivity.otgc.client.domain.model.DynamicUiElement; import org.openconnectivity.otgc.client.domain.model.SerializableResource; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/ResourceViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/ResourceViewModel.java index 4d69410186706132b4965a38586769f52bc409e7..93cad59a03e1e594a2a1397a622ed9ed86066729 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/ResourceViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/client/presentation/viewmodel/ResourceViewModel.java @@ -22,9 +22,9 @@ package org.openconnectivity.otgc.client.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; import org.iotivity.base.OcRepresentation; import org.openconnectivity.otgc.client.domain.usecase.CancelObservation; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/constant/OcfResourceType.java b/otgc/src/main/java/org/openconnectivity/otgc/common/constant/OcfResourceType.java index 65831c2177e6d14565b6a2a28ea4671579d1e680..ed9509f0b918aee36ba0cccf8154865b21d57091 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/constant/OcfResourceType.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/constant/OcfResourceType.java @@ -22,6 +22,9 @@ package org.openconnectivity.otgc.common.constant; +import java.util.ArrayList; +import java.util.List; + public class OcfResourceType { private OcfResourceType() { @@ -30,12 +33,24 @@ public class OcfResourceType { private static final String OIC_WK_PREFIX = "oic.wk."; public static final String DEVICE = OIC_WK_PREFIX + "d"; + public static final String DEVICE_CONF = OIC_WK_PREFIX + "con"; public static final String PLATFORM = OIC_WK_PREFIX + "p"; + public static final String PLATFORM_CONF = OIC_WK_PREFIX + "con.p"; + public static final String RES = OIC_WK_PREFIX + "res"; + public static final String RESOURCE_DIRECTORY = OIC_WK_PREFIX + "rd"; + public static final String MAINTENANCE = OIC_WK_PREFIX + "mnt"; public static final String INTROSPECTION = OIC_WK_PREFIX + "introspection"; public static final String INTROSPECTION_PAYLOAD = OIC_WK_PREFIX + "introspection.payload"; private static final String OIC_RT_PREFIX = "oic.r."; + public static final String ICON = OIC_RT_PREFIX + "icon"; public static final String DOXM = OIC_RT_PREFIX + "doxm"; + public static final String PSTAT = OIC_RT_PREFIX + "pstat"; + public static final String ACL2 = OIC_RT_PREFIX + "acl2"; + public static final String CRED = OIC_RT_PREFIX + "cred"; + public static final String CRL = OIC_RT_PREFIX + "crl"; + public static final String CSR = OIC_RT_PREFIX + "csr"; + public static final String ROLES = OIC_RT_PREFIX + "roles"; public static final String ACCELERATION_SENSOR = OIC_RT_PREFIX + "sensor.acceleration"; public static final String ACTIVITY_COUNT_SENSOR = OIC_RT_PREFIX + "sensor.activity.count"; public static final String AIR_QUALITY = OIC_RT_PREFIX + "airquality"; @@ -122,4 +137,30 @@ public class OcfResourceType { public static final String WATER_SENSOR = OIC_RT_PREFIX + "sensor.water"; public static final String WEIGHT = OIC_RT_PREFIX + "weight"; + private static final List NON_VERTICAL_RESOURCE_TYPES; + static { + NON_VERTICAL_RESOURCE_TYPES = new ArrayList<>(); + + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.DEVICE); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.DEVICE_CONF); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.PLATFORM); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.PLATFORM_CONF); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.RES); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.RESOURCE_DIRECTORY); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.MAINTENANCE); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.ICON); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.INTROSPECTION); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.INTROSPECTION_PAYLOAD); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.DOXM); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.PSTAT); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.ACL2); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.CRED); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.CRL); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.CSR); + NON_VERTICAL_RESOURCE_TYPES.add(OcfResourceType.ROLES); + } + + public static boolean isVerticalResourceType(String resourceType) { + return !NON_VERTICAL_RESOURCE_TYPES.contains(resourceType); + } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/DeviceEntity.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/DeviceEntity.java index 07eb8c04802fec75a500024affdcacec075c5cb8..99d080479a033bf7ccd9bd023893572e03ec5cc7 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/DeviceEntity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/DeviceEntity.java @@ -22,10 +22,10 @@ package org.openconnectivity.otgc.common.data.entity; -import android.arch.persistence.room.ColumnInfo; -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.PrimaryKey; -import android.support.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.PrimaryKey; +import androidx.annotation.NonNull; import java.util.List; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/UserEntity.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/UserEntity.java index b1f8f1810c72a7c52ce253be978e01525b485088..466ccf2b2d6667b1d24f6cca2cc8f8fb44bf36fa 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/UserEntity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/entity/UserEntity.java @@ -22,11 +22,11 @@ package org.openconnectivity.otgc.common.data.entity; -import android.arch.persistence.room.ColumnInfo; -import android.arch.persistence.room.Entity; -import android.arch.persistence.room.Ignore; -import android.arch.persistence.room.PrimaryKey; -import android.support.annotation.NonNull; +import androidx.room.ColumnInfo; +import androidx.room.Entity; +import androidx.room.Ignore; +import androidx.room.PrimaryKey; +import androidx.annotation.NonNull; import java.util.UUID; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/DeviceDao.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/DeviceDao.java index 7513b9ab2c6b7bff17570cf211a94cc046aae8ee..0a08c951d52dba4f92cbd4196501382834e3f577 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/DeviceDao.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/DeviceDao.java @@ -22,11 +22,11 @@ package org.openconnectivity.otgc.common.data.persistence.dao; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; -import android.arch.persistence.room.Update; +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; +import androidx.room.Update; import org.openconnectivity.otgc.common.data.entity.DeviceEntity; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/UserDao.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/UserDao.java index ecf255de1c4eaaae64437138a9cfb86a39854533..f26fc5f96b7dd5ef09f466901d8a206dba8a4db7 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/UserDao.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/dao/UserDao.java @@ -22,10 +22,10 @@ package org.openconnectivity.otgc.common.data.persistence.dao; -import android.arch.persistence.room.Dao; -import android.arch.persistence.room.Insert; -import android.arch.persistence.room.OnConflictStrategy; -import android.arch.persistence.room.Query; +import androidx.room.Dao; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; import org.openconnectivity.otgc.common.data.entity.UserEntity; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/Converters.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/Converters.java index 685c477acecbb6f5210f4b9619ab5075df59eaa0..9c37242249c056651a15949dd89f8f6204bf7ceb 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/Converters.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/Converters.java @@ -22,7 +22,7 @@ package org.openconnectivity.otgc.common.data.persistence.database; -import android.arch.persistence.room.TypeConverter; +import androidx.room.TypeConverter; import com.fasterxml.jackson.core.type.TypeReference; import com.google.gson.Gson; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/OtgcDb.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/OtgcDb.java index 2d813ab5e545c80353ebd6469e355f1900fd4129..181e23666f84156c1150b389cfe257a25387651b 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/OtgcDb.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/persistence/database/OtgcDb.java @@ -22,9 +22,9 @@ package org.openconnectivity.otgc.common.data.persistence.database; -import android.arch.persistence.room.Database; -import android.arch.persistence.room.RoomDatabase; -import android.arch.persistence.room.TypeConverters; +import androidx.room.Database; +import androidx.room.RoomDatabase; +import androidx.room.TypeConverters; import org.openconnectivity.otgc.common.data.entity.DeviceEntity; import org.openconnectivity.otgc.common.data.entity.UserEntity; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/IotivityRepository.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/IotivityRepository.java index fc8fec21845f809b4420b3368a34d955e8e152a3..7f39cafd32b3cdeb010085a30819dd17cfd89348 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/IotivityRepository.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/IotivityRepository.java @@ -24,7 +24,7 @@ package org.openconnectivity.otgc.common.data.repository; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import android.util.ArrayMap; import org.iotivity.base.ErrorCode; @@ -38,9 +38,14 @@ import org.iotivity.base.OcResource; import org.iotivity.base.OcSecureResource; import org.iotivity.base.OxmType; +import org.iotivity.ca.CaInterface; +import org.iotivity.ca.OicCipher; import org.openconnectivity.otgc.common.constant.OcfResourceType; import org.openconnectivity.otgc.common.data.entity.DeviceEntity; import org.openconnectivity.otgc.common.data.persistence.dao.DeviceDao; +import org.openconnectivity.otgc.common.domain.model.OcDevice; +import org.openconnectivity.otgc.devicelist.domain.model.Device; +import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -50,6 +55,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.TimeUnit; import javax.inject.Inject; import javax.inject.Singleton; @@ -88,7 +94,6 @@ public class IotivityRepository { private final DeviceDao deviceDao; private List mUnownedDevices = new ArrayList<>(); - private List mOwnedDevices = new ArrayList<>(); @Inject public IotivityRepository(Context ctx, DeviceDao deviceDao) { @@ -112,13 +117,16 @@ public class IotivityRepository { } } - public Observable scanUnownedDevices() { + public Observable scanUnownedDevices() { return Observable.create(emitter -> { try { mUnownedDevices = OcProvisioning.discoverUnownedDevices(getDiscoveryTimeout()); for (OcSecureResource ocSecureResource : mUnownedDevices) { - emitter.onNext(ocSecureResource); + emitter.onNext(new Device(DeviceType.UNOWNED, + ocSecureResource.getDeviceID(), + new OcDevice(), + ocSecureResource)); } } catch (OcException e) { Timber.e(e); @@ -128,37 +136,47 @@ public class IotivityRepository { }); } - public Observable scanOwnedDevices() { - return Observable.create(emitter -> { - try { - mOwnedDevices = OcProvisioning.discoverOwnedDevices(getDiscoveryTimeout()); - - for (OcSecureResource ocSecureResource : mOwnedDevices) { - emitter.onNext(ocSecureResource); - } - } catch (OcException e) { - Timber.e(e); - emitter.onError(e); + public Observable scanOwnedDevices() { + return findObsResources("") + .timeout(getDiscoveryTimeout() + 5_00L, TimeUnit.SECONDS) + .map(ocResources -> ocResources.get(0)) + .filter(ocResource -> { + boolean isNotUnowned = true; + for (OcSecureResource secureResource : mUnownedDevices) { + if (secureResource.getDeviceID().equals(ocResource.getServerId())) { + isNotUnowned = false; + } + } + return isNotUnowned; + }) + .filter(ocResource -> !ocResource.getServerId().equals(getDeviceId())) + .flatMapSingle(ocResource -> findDeviceInUnicast(ocResource.getServerId())); } - emitter.onComplete(); - }); - } - private Observable> findObsResources(String host) { - return Observable.create(emitter -> { - try { - OcPlatform.findResources(host, - OcPlatform.WELL_KNOWN_QUERY, - CONNECTIVITY_TYPES, + private Observable> findObsResources(String host) { + return Observable.create(emitter -> { + try { + OcPlatform.findResources(host, + OcPlatform.WELL_KNOWN_QUERY, + CONNECTIVITY_TYPES, new OcPlatform.OnResourcesFoundListener() { @Override public void onResourcesFound(OcResource[] ocResources) { DeviceEntity device = deviceDao.findById(ocResources[0].getServerId()).blockingGet(); + List hosts = new ArrayList<>(); + for (OcResource ocResource : ocResources) { + for (String host : ocResource.getAllHosts()) { + if (!hosts.contains(host)) { + hosts.add(host); + } + } + } + if (device == null) { - deviceDao.insert(new DeviceEntity(ocResources[0].getServerId(), "", ocResources[0].getAllHosts())); + deviceDao.insert(new DeviceEntity(ocResources[0].getServerId(), "", hosts)); } else { - deviceDao.update(new DeviceEntity(device.getId(), device.getName(), ocResources[0].getAllHosts())); + deviceDao.update(new DeviceEntity(device.getId(), device.getName(), hosts)); } emitter.onNext(Arrays.asList(ocResources)); } @@ -197,46 +215,68 @@ public class IotivityRepository { return findObsResources("").ignoreElements(); } - public Observable scanOwnedByOtherDevices() { - return findObsResources("") - .map(ocResources -> ocResources.get(0)) - .filter(ocResource -> { - boolean isNotUnowned = true; - for (OcSecureResource secureResource : mUnownedDevices) { - if (secureResource.getDeviceID().equals(ocResource.getServerId())) { - isNotUnowned = false; - } - } - return isNotUnowned; - }) - .filter(ocResource -> { - boolean isNotOwned = true; - for (OcSecureResource secureResource : mOwnedDevices) { - if (secureResource.getDeviceID().equals(ocResource.getServerId())) { - isNotOwned = false; - } - } - return isNotOwned; - }) - .filter(ocResource -> !ocResource.getServerId().equals(getDeviceId())) - .flatMapSingle(ocResource -> findOcSecureResource(ocResource.getServerId())); - } - private String getDeviceId() { ByteBuffer bb = ByteBuffer.wrap(OcPlatform.getDeviceId()); UUID uuid = new UUID(bb.getLong(), bb.getLong()); return uuid.toString(); } - public Single findOcSecureResource(@NonNull String deviceId) { + private OcSecureResource getOcSecureResource(@NonNull String deviceId, boolean filterOwnedByMe) { + try { + String host = getDeviceCoapsIpv6Host(deviceId).blockingGet(); + if (host != null) { + String address; + int port; + EnumSet connType = EnumSet.of(OcConnectivityType.CT_ADAPTER_IP); + + if (host.contains(".")) { + connType.add(OcConnectivityType.CT_IP_USE_V4); + address = host.split("//")[1].split(":")[0]; + port = Integer.valueOf(host.split("//")[1].split(":")[1]); + } else { + connType.add(OcConnectivityType.CT_IP_USE_V6); + address = host.split("\\[")[1].split("]")[0].replace("%25", "%"); + port = Integer.valueOf(host.split("]")[1].split(":")[1]); + } + + return OcProvisioning.discoverSingleDeviceInSecureUnicast(filterOwnedByMe, getDiscoveryTimeout(), deviceId, address, port, connType); + } + } catch (OcException|NullPointerException e) { + Timber.e(e); + return null; + } + + return null; + } + + public void setPreferredCiphersuite(OicCipher cipher) { + CaInterface.setCipherSuite(cipher, OcConnectivityType.CT_ADAPTER_IP); + } + + private Single retrieveOcSecureResource(@NonNull String deviceId, @NonNull OicCipher cipher) { return Single.create(emitter -> { - try { - OcSecureResource ocSecureResource = - OcProvisioning.discoverSingleDevice(getDiscoveryTimeout(), deviceId); + setPreferredCiphersuite(cipher); + OcSecureResource ocSecureResource = getOcSecureResource(deviceId, false); + if (ocSecureResource != null) { emitter.onSuccess(ocSecureResource); - } catch (OcException e) { - Timber.e(e); - emitter.onError(e); + } else { + emitter.onError(new Exception("Find OcSecureResource has failed")); + } + }); + } + + public Single findOcSecureResource(@NonNull String deviceId) { + return retrieveOcSecureResource(deviceId, OicCipher.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) + .onErrorResumeNext(error -> retrieveOcSecureResource(deviceId, OicCipher.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8)); + } + + public Single findDeviceInUnicast(@NonNull String deviceId) { + return Single.create(emitter -> { + OcSecureResource ocSecureResource = getOcSecureResource(deviceId, true); + if (ocSecureResource != null) { + emitter.onSuccess(new Device(DeviceType.OWNED_BY_SELF, ocSecureResource.getDeviceID(), new OcDevice(), ocSecureResource)); + } else { + emitter.onSuccess(new Device(DeviceType.OWNED_BY_OTHER, deviceId, new OcDevice(), null)); } }); } @@ -310,7 +350,7 @@ public class IotivityRepository { }); } - public Single> findResource(String host) { + public Single> findResources(String host) { return Single.create(emitter -> { try { OcPlatform.findResources(host, @@ -329,8 +369,8 @@ public class IotivityRepository { Timber.d(throwable); } else { Timber.e(throwable); - emitter.onError(throwable); } + emitter.onError(throwable); } }); } catch (OcException ex) { @@ -577,7 +617,7 @@ public class IotivityRepository { return coapsIpv6Host; } - private int getDiscoveryTimeout() { + public int getDiscoveryTimeout() { SharedPreferences wmbPreference = PreferenceManager.getDefaultSharedPreferences(ctx); return Integer.parseInt( diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/PermissionRepository.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/PermissionRepository.java index 53e93df65511227582792957ec0fa3e9bee0617d..8e1ac8b1c22be24aaf44938b98d902bf35df8f74 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/PermissionRepository.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/PermissionRepository.java @@ -25,7 +25,7 @@ package org.openconnectivity.otgc.common.data.repository; import android.Manifest; import android.content.Context; import android.content.pm.PackageManager; -import android.support.v4.content.ContextCompat; +import androidx.core.content.ContextCompat; import java.util.ArrayList; import java.util.List; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/WlanRepository.java b/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/WlanRepository.java index 21b3cc541b4c9a11eb7e9c6113b0fbad97a40cc9..470c7b7dba9342ff8b1e65c626a7ec8bb04d7e3f 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/WlanRepository.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/data/repository/WlanRepository.java @@ -38,7 +38,7 @@ import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiConfiguration.PairwiseCipher; import android.net.wifi.WifiConfiguration.Protocol; import android.net.wifi.WifiManager; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.openconnectivity.otgc.common.data.model.WifiAdapterNotEnabledException; import org.openconnectivity.otgc.common.data.model.WifiNetworkNotEnabledException; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/domain/usecase/InitializeIotivityUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/common/domain/usecase/InitializeIotivityUseCase.java index 0bcdceae4e0758f0fe8a9991b6bf3fa338cf1ce4..fbccf7824f59a6143ee99cd80366160f8f5eb88e 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/domain/usecase/InitializeIotivityUseCase.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/domain/usecase/InitializeIotivityUseCase.java @@ -22,7 +22,7 @@ package org.openconnectivity.otgc.common.domain.usecase; -import android.support.annotation.VisibleForTesting; +import androidx.annotation.VisibleForTesting; import com.upokecenter.cbor.CBOREncodeOptions; import com.upokecenter.cbor.CBORObject; @@ -132,7 +132,10 @@ public class InitializeIotivityUseCase { setDeviceUuid(jsonObject, uuid); X509Certificate caCertificate = mIORepository.getAssetAsX509Certificate(CRT_FILE).blockingGet(); PrivateKey caPrivateKey = mIORepository.getAssetAsPrivateKey(PRIVATE_KEY_FILE).blockingGet(); - addTrustCa(jsonObject, uuid, bytesToHex(caCertificate.getEncoded())); + ASN1Sequence pkSeqCa = (ASN1Sequence)ASN1Sequence.fromByteArray(caPrivateKey.getEncoded()); + PrivateKeyInfo pkInfoCa = PrivateKeyInfo.getInstance(pkSeqCa); + ECPrivateKey devPrivateKeyCa = ECPrivateKey.getInstance(pkInfoCa.parsePrivateKey()); + addTrustCa(jsonObject, uuid,bytesToHex(devPrivateKeyCa.getEncoded()), bytesToHex(caCertificate.getEncoded())); // public/private key pair that we are creating certificate for ECGenParameterSpec ecParamSpec = new ECGenParameterSpec("secp256r1"); @@ -227,8 +230,8 @@ public class InitializeIotivityUseCase { jsonObject.getJSONObject("doxm").put("deviceuuid", deviceUuid); } - private void addTrustCa(JSONObject jsonObject, String deviceUuid, String derCertificate) throws JSONException { - addCertificate(jsonObject, deviceUuid, 2, derCertificate, null, "oic.sec.cred.trustca"); + private void addTrustCa(JSONObject jsonObject, String deviceUuid, String rawPrivateKey, String derCertificate) throws JSONException { + addCertificate(jsonObject, deviceUuid, 2, derCertificate, rawPrivateKey, "oic.sec.cred.trustca"); } private void addCert(JSONObject jsonObject, String deviceUuid, String rawPrivateKey, String derCertificate) throws JSONException { @@ -256,7 +259,7 @@ public class InitializeIotivityUseCase { credObject.put("publicdata", publicDataObject); if (rawPrivateKey != null && - (credUsage.equals("oic.sec.cred.cert") || credUsage.equals("oic.sec.cred.mfgcert"))) { + (credUsage.equals("oic.sec.cred.cert") || credUsage.equals("oic.sec.cred.mfgcert") || credUsage.equals("oic.sec.cred.trustca"))) { JSONObject privateDataObject = new JSONObject(); privateDataObject.put("encoding", "oic.sec.encoding.raw"); privateDataObject.put("data", rawPrivateKey); diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/logger/FileLoggingTree.java b/otgc/src/main/java/org/openconnectivity/otgc/common/logger/FileLoggingTree.java index 73bd49187d531696387c79f1fa7ad0242353114f..8e3b24c81c1fe228311697c47049e2f42d47eb2e 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/logger/FileLoggingTree.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/logger/FileLoggingTree.java @@ -20,7 +20,9 @@ package org.openconnectivity.otgc.common.logger; import android.content.Context; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; + +import android.os.Environment; import android.util.Log; import android.util.SparseArray; @@ -52,6 +54,55 @@ public class FileLoggingTree extends Timber.DebugTree { public FileLoggingTree(Context context) { mContext = context; + + storeLogsInFile(); + } + + private void storeLogsInFile() + { + if ( isExternalStorageWritable() ) { + String fileNameTimeStamp = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); + + File appDirectory = new File( mContext.getExternalFilesDir(null).toString() ); + File logDirectory = new File( appDirectory + "/log" ); + File logFile = new File( logDirectory, "logcat" + fileNameTimeStamp + ".html"); + + // create app folder + if ( !appDirectory.exists() ) { + appDirectory.mkdir(); + } + + // create log folder + if ( !logDirectory.exists() ) { + logDirectory.mkdir(); + } + + // clear the previous logcat and then write the new one to the file + try { + Process process = Runtime.getRuntime().exec("logcat -c"); + process = Runtime.getRuntime().exec("logcat -f " + logFile); + } catch ( IOException e ) { + Timber.e(e); + } + + } else if ( isExternalStorageReadable() ) { + // only readable + } else { + // not accessible + } + } + + /* Checks if external storage is available for read and write */ + public boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + return Environment.MEDIA_MOUNTED.equals( state ); + } + + /* Checks if external storage is available to at least read */ + public boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + return ( Environment.MEDIA_MOUNTED.equals( state ) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals( state ) ); } @Override diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/EmptyRecyclerView.java b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/EmptyRecyclerView.java index 05ce12f6e805f2780f5a327886b3ff467d63dba9..321e0eba1544a5a19d239d8522cc717744335a2c 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/EmptyRecyclerView.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/EmptyRecyclerView.java @@ -23,8 +23,8 @@ package org.openconnectivity.otgc.common.presentation.view; import android.content.Context; -import android.support.annotation.Nullable; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; import android.util.AttributeSet; import android.view.View; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/RecyclerWithSwipeFragment.java b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/RecyclerWithSwipeFragment.java index e49242458beae9cdf60dae5e9137e9c3d3061ac1..a085e04d0e478cd17372caa005355fcfb4f26b1d 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/RecyclerWithSwipeFragment.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/view/RecyclerWithSwipeFragment.java @@ -21,14 +21,15 @@ */ package org.openconnectivity.otgc.common.presentation.view; -import android.arch.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProvider; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.Fragment; -import android.support.v4.content.ContextCompat; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.selection.SelectionTracker; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/BaseViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/BaseViewModel.java index 672a01a854c74b3ba40dc3460f1ea4d29511f6e4..441caabcb51dbc8a064ce8553ce6bf14702d145b 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/BaseViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/BaseViewModel.java @@ -1,8 +1,8 @@ package org.openconnectivity.otgc.common.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; import io.reactivex.disposables.CompositeDisposable; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/Response.java b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/Response.java index 4dcfbc6b128a23d09a4bcf92c4df60e09713e6a5..035fcdcda373153205575a532a02b3f879e1e138 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/Response.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/Response.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.common.presentation.viewmodel; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * a generic class that describes a data with a status diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelError.java b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelError.java index 3a056d8d3ff0c1dcf7dc190ec6f8c7f608b8d602..c1b5f47831bd53309f631476e1ab4ebd048a3228 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelError.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelError.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.common.presentation.viewmodel; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; public class ViewModelError { @NonNull private final ViewModelErrorType mType; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelFactory.java b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelFactory.java index d424a5a2c608364e8dc39a57f251a658f9b1ea56..4b8c2edb1758cb7878310929766b19fe31569b0a 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelFactory.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/common/presentation/viewmodel/ViewModelFactory.java @@ -22,9 +22,9 @@ package org.openconnectivity.otgc.common.presentation.viewmodel; -import android.arch.lifecycle.ViewModel; -import android.arch.lifecycle.ViewModelProvider; -import android.support.annotation.NonNull; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; +import androidx.annotation.NonNull; import java.util.Map; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredActivity.java index 144857b0a09d797027d58c5cd57f225d5487535f..b1c733bc7151570878c34d11a3025559ed911157 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredActivity.java @@ -22,14 +22,14 @@ package org.openconnectivity.otgc.credential.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.view.View; import android.widget.EditText; import android.widget.RadioButton; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialAdapter.java b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialAdapter.java index b9232841b34834251ab75da73f309fc716e82b65..aaa481aa2e46f38b8692136339ff73962494864c 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialAdapter.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialAdapter.java @@ -23,9 +23,9 @@ package org.openconnectivity.otgc.credential.presentation.view; import android.content.Context; -import android.support.annotation.NonNull; -import android.support.v7.util.SortedList; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.SortedList; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialsActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialsActivity.java index 06ad9d55e209cb471a667bf1f3eea89c671a95ab..303ea78957ee7ef2d7447f21922d0be53c24f342 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialsActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/view/CredentialsActivity.java @@ -22,17 +22,17 @@ package org.openconnectivity.otgc.credential.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; import android.view.View; import android.widget.ProgressBar; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredViewModel.java index cb96214b1d152a0bbf521548469ef5c61398885c..e9179ff97a5c3d77233bc15c0d7de0e572a19033 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredViewModel.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.credential.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import org.openconnectivity.otgc.common.domain.rx.SchedulersFacade; import org.openconnectivity.otgc.common.presentation.viewmodel.BaseViewModel; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredentialsViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredentialsViewModel.java index d0e01ab3ee04538d67634c85e6bd34b09e5dceee..5f42dac6e31f9f74482f5090f64a217e4d419c39 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredentialsViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/credential/presentation/viewmodel/CredentialsViewModel.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.credential.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import org.iotivity.base.OicSecCred; import org.openconnectivity.otgc.common.presentation.viewmodel.BaseViewModel; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/DoxsRepository.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/DoxsRepository.java index 8770fc83654e2c5037c7404d9523f92899bfee9c..a8b32c9c1a734427caf07d16bd6a439cc930b8c0 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/DoxsRepository.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/DoxsRepository.java @@ -22,11 +22,20 @@ package org.openconnectivity.otgc.devicelist.data.repository; +import org.iotivity.base.AceSubjectType; +import org.iotivity.base.CredType; +import org.iotivity.base.KeySize; import org.iotivity.base.OcException; import org.iotivity.base.OcSecureResource; +import org.iotivity.base.OicSecAce; +import org.iotivity.base.OicSecAceSubject; +import org.iotivity.base.OicSecAcl; +import org.iotivity.base.OicSecResr; import org.iotivity.base.OxmType; import java.io.IOException; +import java.util.ArrayList; +import java.util.EnumSet; import java.util.List; import javax.inject.Inject; @@ -96,4 +105,45 @@ public class DoxsRepository { emitter.onComplete(); }); } + + public Completable pairwiseDevices(OcSecureResource clientResource, OcSecureResource serverResource, List resources) { + return Completable.create(emitter -> { + try { + // Create ACE to allow client to manage the server + List aces = new ArrayList<>(); + OicSecAceSubject subject = new OicSecAceSubject(AceSubjectType.SUBJECT_UUID.getValue(), clientResource.getDeviceID(), null, null); + OicSecAce ace = new OicSecAce(0, subject, 31, resources, new ArrayList<>()); + aces.add(ace); + OicSecAcl acl = new OicSecAcl(null, aces); + + EnumSet credTypes = EnumSet.of(CredType.SYMMETRIC_PAIR_WISE_KEY); + clientResource.provisionPairwiseDevices(credTypes, KeySize.OWNER_PSK_LENGTH_256, null, serverResource, acl, (results, hasError) -> + { + if (hasError == 0) { + emitter.onComplete(); + } else { + emitter.onError(new IOException("Link Devices Exception")); + } + }); + } catch (OcException e) { + emitter.onError(e); + } + }); + } + + + public Completable unlinkDevices(OcSecureResource serverOcSecureResource, OcSecureResource clientOcSecureResource) { + return Completable.create(emitter -> + serverOcSecureResource.unlinkDevices( + clientOcSecureResource, + (provisionResults, hasError) -> { + if (hasError == 0) { + emitter.onComplete(); + } else { + emitter.onError(new IOException("Error")); + } + } + ) + ); + } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/EasySetupRepository.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/EasySetupRepository.java index c2beb3f8e2ccff716fde49501291f4a09bafcb82..f6cda7180a57606ec02334f57e991d08839c0b97 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/EasySetupRepository.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/data/repository/EasySetupRepository.java @@ -24,7 +24,7 @@ package org.openconnectivity.otgc.devicelist.data.repository; import android.content.Context; import android.os.Build; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; import org.iotivity.base.OcResource; import org.iotivity.service.easysetup.mediator.DeviceProp; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/model/Device.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/model/Device.java index 824b98e9614fbd5ac17434d60f6a6a03e9a89005..56b05e2459a7c6309d85800f1dace03e1cc4865d 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/model/Device.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/model/Device.java @@ -30,6 +30,7 @@ import org.openconnectivity.otgc.common.domain.model.OcDevice; public class Device { private DeviceType mType; + private Role mRole; private String mDeviceId; private OcDevice mDeviceInfo; private OcSecureResource mOcSecureResource; @@ -38,6 +39,7 @@ public class Device { super(); this.mType = type; + this.mRole = Role.UNKNOWN; this.mDeviceId = deviceId; this.mDeviceInfo = deviceInfo; this.mOcSecureResource = ocSecureResource; @@ -51,6 +53,14 @@ public class Device { this.mType = type; } + public Role getRole() { + return mRole; + } + + public void setRole(Role role) { + this.mRole = role; + } + public String getDeviceId() { return mDeviceId; } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/model/Role.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/model/Role.java new file mode 100644 index 0000000000000000000000000000000000000000..94398ba884047e8dd58f573ea4366c0e21f83d68 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/model/Role.java @@ -0,0 +1,29 @@ +/* + * ***************************************************************** + * + * Copyright 2018 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.devicelist.domain.model; + +public enum Role { + CLIENT, + SERVER, + UNKNOWN +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/GetDeviceRoleUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/GetDeviceRoleUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..d645cd4f3339cd870a838da89154c0851e655930 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/GetDeviceRoleUseCase.java @@ -0,0 +1,66 @@ +/* + * ***************************************************************** + * + * Copyright 2018 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.devicelist.domain.usecase; + +import org.iotivity.base.OcResource; +import org.openconnectivity.otgc.common.constant.OcfResourceType; +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; +import org.openconnectivity.otgc.devicelist.domain.model.Role; + +import java.util.concurrent.TimeUnit; + +import javax.inject.Inject; + +import io.reactivex.Single; + +public class GetDeviceRoleUseCase { + private final IotivityRepository mIotivityRepository; + + @Inject + GetDeviceRoleUseCase(IotivityRepository iotivityRepository) { + this.mIotivityRepository = iotivityRepository; + } + + public Single execute(String deviceId) { + return mIotivityRepository.getDeviceCoapIpv6Host(deviceId) + .flatMap(mIotivityRepository::findResources) + .timeout(mIotivityRepository.getDiscoveryTimeout() + 5_00L, TimeUnit.SECONDS) + .map(ocResources -> { + Role deviceRole = Role.CLIENT; + for (OcResource resource : ocResources) { + for (String resourceType : resource.getResourceTypes()) { + if (OcfResourceType.isVerticalResourceType(resourceType)) { + deviceRole = Role.SERVER; + break; + } + } + + if (deviceRole.equals(Role.SERVER)) { + break; + } + } + + return deviceRole; + }); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OffboardUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OffboardUseCase.java index a139ee7a882f4298ca73a303e2c893c671039714..09e89c2bfb8e86d3fbc28d43f43520f441849125 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OffboardUseCase.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OffboardUseCase.java @@ -26,8 +26,6 @@ import org.iotivity.base.OcSecureResource; import org.openconnectivity.otgc.common.data.repository.PreferencesRepository; import org.openconnectivity.otgc.devicelist.data.repository.DoxsRepository; import org.openconnectivity.otgc.devicelist.domain.model.Device; -import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; -import org.openconnectivity.otgc.common.domain.model.OcDevice; import org.openconnectivity.otgc.common.data.repository.IotivityRepository; import java.util.concurrent.TimeUnit; @@ -51,11 +49,11 @@ public class OffboardUseCase { } public Single execute(OcSecureResource deviceToOffboard) { - final Single getUpdatedOcSecureResource = + final Single getUpdatedOcSecureResource = iotivityRepository.scanUnownedDevices() - .filter(ocSecureResource -> - (ocSecureResource.getDeviceID().equals(deviceToOffboard.getDeviceID()) - || ocSecureResource.getIpAddr().equals(deviceToOffboard.getIpAddr()))) + .filter(device -> + (device.getDeviceId().equals(deviceToOffboard.getDeviceID()) + || device.getOcSecureResource().getIpAddr().equals(deviceToOffboard.getIpAddr()))) .singleOrError(); return mDoxsRepository.resetDevice(deviceToOffboard, @@ -64,12 +62,6 @@ public class OffboardUseCase { .andThen(getUpdatedOcSecureResource) .onErrorResumeNext(error -> getUpdatedOcSecureResource .retry(2) - .onErrorResumeNext(Single.error(error))) - .map(ocSecureResource -> - new Device(DeviceType.UNOWNED, - ocSecureResource.getDeviceID(), - new OcDevice(), - ocSecureResource) - ); + .onErrorResumeNext(Single.error(error))); } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OnboardUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OnboardUseCase.java index 5ff765d9aab91fa4e4c5b0d1fc5183da2d4de8a0..b4941b3059dd69101c9a50e6cb09df45a526c473 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OnboardUseCase.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/OnboardUseCase.java @@ -25,7 +25,6 @@ import org.iotivity.base.OcSecureResource; import org.openconnectivity.otgc.devicelist.data.repository.DoxsRepository; import org.openconnectivity.otgc.devicelist.domain.model.Device; import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; -import org.openconnectivity.otgc.common.domain.model.OcDevice; import org.openconnectivity.otgc.common.data.repository.IotivityRepository; import java.util.concurrent.TimeUnit; @@ -33,6 +32,7 @@ import java.util.concurrent.TimeUnit; import javax.inject.Inject; import io.reactivex.Single; +import io.reactivex.Observable; public class OnboardUseCase { private final DoxsRepository mDoxsRepository; @@ -46,23 +46,17 @@ public class OnboardUseCase { } public Single execute(OcSecureResource deviceToOnboard) { - final Single getUpdatedOcSecureResource = - iotivityRepository.scanOwnedDevices() - .filter(ocSecureResource -> - (ocSecureResource.getDeviceID().equals(deviceToOnboard.getDeviceID()) - || ocSecureResource.getIpAddr().equals(deviceToOnboard.getIpAddr()))) - .singleOrError(); + final Single getUpdatedOcSecureResource = Observable.concat(iotivityRepository.scanOwnedDevices(), iotivityRepository.scanUnownedDevices()) + .filter(device -> device.getType() == DeviceType.OWNED_BY_SELF + && (device.getDeviceId().equals(deviceToOnboard.getDeviceID()) + || device.getOcSecureResource().getIpAddr().equals(deviceToOnboard.getIpAddr()))) + .singleOrError(); return mDoxsRepository.doOwnershipTransfer(deviceToOnboard) .delay(1, TimeUnit.SECONDS) .andThen(getUpdatedOcSecureResource) .onErrorResumeNext(error -> getUpdatedOcSecureResource .retry(2) - .onErrorResumeNext(Single.error(error))) - .map(ocSecureResource -> - new Device(DeviceType.OWNED_BY_SELF, - ocSecureResource.getDeviceID(), - new OcDevice(), - ocSecureResource)); + .onErrorResumeNext(Single.error(error))); } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/PairwiseDevicesUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/PairwiseDevicesUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..1c7d4056b1c40e7d4048bb79549271236b084991 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/PairwiseDevicesUseCase.java @@ -0,0 +1,60 @@ +/* + * ***************************************************************** + * + * Copyright 2018 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.devicelist.domain.usecase; + +import org.iotivity.base.OcSecureResource; +import org.openconnectivity.otgc.client.data.repository.ResourceRepository; +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; +import org.openconnectivity.otgc.devicelist.data.repository.DoxsRepository; + +import javax.inject.Inject; + +import io.reactivex.Completable; +import io.reactivex.Single; + +public class PairwiseDevicesUseCase { + private final IotivityRepository mIotivityRepository; + private final DoxsRepository mDoxsRepository; + private final ResourceRepository mResourceRepository; + + @Inject + PairwiseDevicesUseCase(IotivityRepository iotivityRepository, + DoxsRepository doxsRepository, + ResourceRepository resourceRepository) { + this.mIotivityRepository = iotivityRepository; + this.mDoxsRepository = doxsRepository; + this.mResourceRepository = resourceRepository; + } + + public Completable execute(String serverId, String clientId) { + Single clientSecureResource = mIotivityRepository.findOcSecureResource(clientId); + Single serverSecureResource = mIotivityRepository.findOcSecureResource(serverId); + + return mIotivityRepository.getDeviceCoapIpv6Host(serverId) + .flatMap(mIotivityRepository::findResources) + .map(mResourceRepository::getVerticalResources) + .flatMapCompletable(resources -> Single.concat(clientSecureResource, serverSecureResource).toList() + .flatMapCompletable(ocSecureResources -> mDoxsRepository.pairwiseDevices(ocSecureResources.get(0), ocSecureResources.get(1), resources))); + + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/ScanDevicesUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/ScanDevicesUseCase.java index ae9e3cb6e9130d08af29c6317ee503f5cbd01ba2..2e7e8d1262b592c7d4ccc46d5d384a4a2cd58fe0 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/ScanDevicesUseCase.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/ScanDevicesUseCase.java @@ -22,8 +22,6 @@ package org.openconnectivity.otgc.devicelist.domain.usecase; import org.openconnectivity.otgc.devicelist.domain.model.Device; -import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; -import org.openconnectivity.otgc.common.domain.model.OcDevice; import org.openconnectivity.otgc.common.data.repository.IotivityRepository; import javax.inject.Inject; @@ -39,33 +37,11 @@ public class ScanDevicesUseCase { } public Observable execute() { - Observable unownedObservable = mIotivityRepository.scanUnownedDevices() - .map(ocSecureResource -> - new Device(DeviceType.UNOWNED, - ocSecureResource.getDeviceID(), - new OcDevice(), - ocSecureResource) - ); - - Observable ownedObservable = mIotivityRepository.scanOwnedDevices() - .map(ocSecureResource -> - new Device(DeviceType.OWNED_BY_SELF, - ocSecureResource.getDeviceID(), - new OcDevice(), - ocSecureResource) - ); - - Observable ownedByOtherObservable = mIotivityRepository.scanOwnedByOtherDevices() - .map(ocSecureResource -> - new Device( - DeviceType.OWNED_BY_OTHER, - ocSecureResource.getDeviceID(), - new OcDevice(), - ocSecureResource) - ); + Observable unownedObservable = mIotivityRepository.scanUnownedDevices(); + Observable ownedObservable = mIotivityRepository.scanOwnedDevices(); return mIotivityRepository.scanHosts() .andThen(Observable.concat(unownedObservable, - ownedObservable, ownedByOtherObservable)); + ownedObservable)); } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/SetRfotmModeUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/SetRfotmModeUseCase.java index 97e4218c01625f6473907bd880020e81e3b63eb5..b456223af0ecfce2a64b73772fa3df3b564eddc4 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/SetRfotmModeUseCase.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/SetRfotmModeUseCase.java @@ -27,6 +27,7 @@ import org.openconnectivity.otgc.common.data.repository.PreferencesRepository; import org.openconnectivity.otgc.common.data.repository.IotivityRepository; import org.openconnectivity.otgc.common.data.repository.ProvisioningRepository; import org.openconnectivity.otgc.devicelist.data.repository.DoxsRepository; +import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; import java.util.concurrent.TimeUnit; @@ -59,9 +60,10 @@ public class SetRfotmModeUseCase { public Completable execute() { return iotivityRepository.scanOwnedDevices() - .flatMapCompletable(ocSecureResource -> + .filter(device -> device.getType() == DeviceType.OWNED_BY_SELF) + .flatMapCompletable(device -> mDoxsRepository.resetDevice( - ocSecureResource, + device.getOcSecureResource(), mPreferencesRepository.getDiscoveryTimeout())) .delay(500, TimeUnit.MILLISECONDS) .andThen(mProvisioningRepository.resetSvrDb()) diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/UnlinkDevicesUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/UnlinkDevicesUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..6a6373715949ba9f6be49a5bf9c77598a5d9c63f --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/domain/usecase/UnlinkDevicesUseCase.java @@ -0,0 +1,52 @@ +/* + * ***************************************************************** + * + * Copyright 2018 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.devicelist.domain.usecase; + +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; +import org.openconnectivity.otgc.devicelist.data.repository.DoxsRepository; + +import javax.inject.Inject; + +import io.reactivex.Completable; + +public class UnlinkDevicesUseCase { + private final IotivityRepository mIotivityRepository; + private final DoxsRepository mDoxsRepository; + + @Inject + UnlinkDevicesUseCase(IotivityRepository iotivityRepository, + DoxsRepository doxsRepository) { + this.mIotivityRepository = iotivityRepository; + this.mDoxsRepository = doxsRepository; + } + + public Completable execute(String serverId, String clientId) { + return mIotivityRepository.findOcSecureResource(serverId) + .flatMapCompletable(serverOcSecureResource -> + mDoxsRepository.unlinkDevices( + serverOcSecureResource, + mIotivityRepository.findOcSecureResource(clientId).blockingGet() + ) + ); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/ActionModeController.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/ActionModeController.java new file mode 100644 index 0000000000000000000000000000000000000000..628a4bc219755af583159e1cd4107321c35494ed --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/ActionModeController.java @@ -0,0 +1,125 @@ +/* + * ***************************************************************** + * + * Copyright 2018 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.devicelist.presentation.view; + +import android.content.Context; +import android.view.Menu; +import android.view.MenuItem; + +import org.iotivity.base.OcException; +import org.openconnectivity.otgc.R; +import org.openconnectivity.otgc.devicelist.domain.model.Device; +import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; +import org.openconnectivity.otgc.devicelist.domain.model.Role; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import androidx.appcompat.view.ActionMode; +import androidx.recyclerview.selection.SelectionTracker; +import timber.log.Timber; + +public class ActionModeController implements ActionMode.Callback { + private final Context mContext; + private final SelectionTracker mSelectionTracker; + private static MyMenuItemClickListener sMyMenuItemClickListener; + + public ActionModeController(Context context, SelectionTracker selectionTracker) { + this.mContext = context; + this.mSelectionTracker = selectionTracker; + } + + @Override + public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { + actionMode.getMenuInflater().inflate(R.menu.menu_devices_selection, menu); // Inflate the menu over action mode + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { + MenuItem linkMenuItem = menu.findItem(R.id.action_pairwise); + MenuItem unlinkMenuItem = menu.findItem(R.id.action_unlink); + if (mSelectionTracker.hasSelection() && mSelectionTracker.getSelection().size() == 2) { + Device server = null; + Device client = null; + Iterator deviceIterable = mSelectionTracker.getSelection().iterator(); + while (deviceIterable.hasNext()) { + Device device = deviceIterable.next(); + if (device.getRole().equals(Role.SERVER) && device.getType().equals(DeviceType.OWNED_BY_SELF)) { + server = device; + } else if (device.getRole().equals(Role.CLIENT) && device.getType().equals(DeviceType.OWNED_BY_SELF)) { + client = device; + } + } + + if (server != null && client != null) { + try { + List serverLinkedDevices = server.getOcSecureResource().getLinkedDevices(); + List clientLinkedDevices = client.getOcSecureResource().getLinkedDevices(); + + String serverId = server.getDeviceId(); + String clientId = client.getDeviceId(); + if (serverLinkedDevices.contains(clientId) + && clientLinkedDevices.contains(serverId)) { + unlinkMenuItem.setOnMenuItemClickListener(menuItem -> { + actionMode.finish(); + return sMyMenuItemClickListener.onMenuItemClick(menuItem, serverId, clientId); + }); + unlinkMenuItem.setVisible(true); + } else { + linkMenuItem.setOnMenuItemClickListener(menuItem -> { + actionMode.finish(); + return sMyMenuItemClickListener.onMenuItemClick(menuItem, serverId, clientId); + }); + linkMenuItem.setVisible(true); + } + } catch (OcException e) { + Timber.e(e); + } + } + } else { + linkMenuItem.setVisible(false); + unlinkMenuItem.setVisible(false); + } + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode actionMode) { + mSelectionTracker.clearSelection(); + } + + public static void setOnMenuItemClickListener(MyMenuItemClickListener myMenuItemClickListener) { + sMyMenuItemClickListener = myMenuItemClickListener; + } + + public interface MyMenuItemClickListener { + boolean onMenuItemClick(MenuItem menuItem, String serverId, String clientId); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DeviceListActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DeviceListActivity.java index 8646008517e204615ea2596b7064d8e68b5ccde5..ee4f5d69e34afd800712d19b12755ec9e2fb8134 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DeviceListActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DeviceListActivity.java @@ -22,13 +22,13 @@ package org.openconnectivity.otgc.devicelist.presentation.view; import android.app.AlertDialog; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; +import androidx.fragment.app.Fragment; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; import android.view.ContextThemeWrapper; import android.view.Menu; import android.view.MenuItem; @@ -193,6 +193,8 @@ public class DeviceListActivity extends AppCompatActivity implements HasSupportF Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.devices_fragment); if (fragment instanceof RecyclerWithSwipeFragment) { ((RecyclerWithSwipeFragment) fragment).onSwipeRefresh(); + } else if (fragment instanceof DoxsFragment) { + ((DoxsFragment) fragment).onSwipeRefresh(); } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsFragment.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsFragment.java index 12d8673761116937ec104005ff19e6c31edef61f..b3520cbc135ee5f6a91f233f1bfde704cd5f5f37 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsFragment.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsFragment.java @@ -23,12 +23,28 @@ package org.openconnectivity.otgc.devicelist.presentation.view; import android.app.AlertDialog; -import android.arch.lifecycle.ViewModelProviders; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.view.ActionMode; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; -import android.support.annotation.NonNull; -import android.support.design.widget.TextInputEditText; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import com.google.android.material.textfield.TextInputEditText; + +import androidx.recyclerview.selection.OnDragInitiatedListener; +import androidx.recyclerview.selection.SelectionTracker; +import androidx.recyclerview.selection.StorageStrategy; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; @@ -37,7 +53,7 @@ import org.iotivity.base.OxmType; import org.openconnectivity.otgc.R; import org.openconnectivity.otgc.accesscontrol.presentation.view.AccessControlActivity; import org.openconnectivity.otgc.client.presentation.view.GenericClientActivity; -import org.openconnectivity.otgc.common.presentation.view.RecyclerWithSwipeFragment; +import org.openconnectivity.otgc.common.presentation.view.EmptyRecyclerView; import org.openconnectivity.otgc.common.presentation.viewmodel.CommonError; import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelError; import org.openconnectivity.otgc.credential.presentation.view.CredentialsActivity; @@ -46,14 +62,27 @@ import org.openconnectivity.otgc.common.presentation.UiUtils; import org.openconnectivity.otgc.common.presentation.viewmodel.Response; import org.openconnectivity.otgc.devicelist.presentation.viewmodel.SharedViewModel; import org.openconnectivity.otgc.devicelist.presentation.viewmodel.DoxsViewModel; +import org.openconnectivity.otgc.di.Injectable; +import org.openconnectivity.otgc.linkedroles.presentation.view.LinkedRolesActivity; import org.openconnectivity.otgc.wlanscan.domain.model.WifiNetwork; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; +import javax.inject.Inject; + +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import butterknife.BindView; +import butterknife.ButterKnife; import timber.log.Timber; -public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewModel.SelectOxMListener { +public class DoxsFragment extends Fragment implements DoxsViewModel.SelectOxMListener, Injectable { + + @BindView(R.id.swipe_refresh_devices) SwipeRefreshLayout mSwipeToRefreshView; + @BindView(R.id.recycler_ocf_devices) EmptyRecyclerView mRecyclerView; + + @Inject ViewModelProvider.Factory mViewModelFactory; private DoxsListAdapter mAdapter; @@ -69,12 +98,87 @@ public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewM private AlertDialog mConnectWifiDialog = null; + private SelectionTracker mSelectionTracker; + private ActionMode mActionMode; + public DoxsFragment() { // Required empty public constructor } @Override - public RecyclerView.Adapter getAdapter() { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_recycler_with_swipe, container, false); + ButterKnife.bind(this, rootView); + + initViews(); + + return rootView; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + initViewModel(); + } + + private void initViews() { + mRecyclerView.setHasFixedSize(true); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + mRecyclerView.setAdapter(getAdapter()); + mRecyclerView.setEmptyView(null); + + if (getContext() != null) { + mSwipeToRefreshView.setColorSchemeColors(ContextCompat.getColor(getContext(), R.color.colorPrimary)); + } + + mSwipeToRefreshView.setOnRefreshListener(() -> { + mSwipeToRefreshView.setRefreshing(false); + onSwipeRefresh(); + }); + + mSelectionTracker = new SelectionTracker.Builder<>( + "my-selection-id", + mRecyclerView, + new MyItemKeyProvider(1, mAdapter.mDataset), + new MyItemLookup(mRecyclerView), + StorageStrategy.createLongStorage() + ).withOnDragInitiatedListener(e -> { + Timber.d("onDragInitiated"); + return true; + }).build(); + + mAdapter.setSelectionTracker(mSelectionTracker); + + mSelectionTracker.addObserver(new SelectionTracker.SelectionObserver() { + @Override + public void onSelectionChanged() { + super.onSelectionChanged(); + if (mSelectionTracker.hasSelection()) { + if (mActionMode == null) { + ActionModeController actionController = new ActionModeController(getActivity(), mSelectionTracker); + ActionModeController.setOnMenuItemClickListener((menuItem, serverId, clientId) -> { + if (menuItem.getItemId() == R.id.action_pairwise) { + mViewModel.pairwiseDevices(serverId, clientId); + } else if (menuItem.getItemId() == R.id.action_unlink) { + mViewModel.unlinkDevices(serverId, clientId); + } + + return true; + }); + mActionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(actionController); + } else { + mActionMode.invalidate(); + } + mActionMode.setTitle(Integer.toString(mSelectionTracker.getSelection().size())); + } else if (mActionMode != null) { + mActionMode.finish(); + mActionMode = null; + } + } + }); + } + + private RecyclerView.Adapter getAdapter() { mAdapter = new DoxsListAdapter(getContext()); DoxsListAdapter.setOnItemClickListener((position, v) -> { /*switch (mAdapter.mDataset.get(position).getType()) { @@ -97,9 +201,7 @@ public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewM mViewModel.doOwnershipTransfer(mAdapter.mDataset.get(position).getOcSecureResource()); break; case R.id.img_btn_generic_client: - launchGenericClientView( - mAdapter.mDataset.get(position).getOcSecureResource().getIpAddr(), - mAdapter.mDataset.get(position).getDeviceId()); + launchGenericClientView(mAdapter.mDataset.get(position).getDeviceId()); break; } }); @@ -124,6 +226,13 @@ public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewM credIntent.putExtra("deviceId", mAdapter.mDataset.get(position).getDeviceId()); startActivity(credIntent); break; + case R.id.button_roles: + Intent rolesIntent = new Intent(getActivity(), LinkedRolesActivity.class); + rolesIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + rolesIntent.putExtra("deviceId", mAdapter.mDataset.get(position).getDeviceId()); + rolesIntent.putExtra("deviceRole", mAdapter.mDataset.get(position).getRole().toString()); + startActivity(rolesIntent); + break; case R.id.menu_item_wifi_easy_setup: mViewModel.getScanResponse().observe(this, this::processScan); positionWifiEasySetupItem = position; @@ -141,9 +250,8 @@ public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewM return mAdapter; } - @Override - public void initViewModel() { - mViewModel = ViewModelProviders.of(this, getViewModelFactory()).get(DoxsViewModel.class); + private void initViewModel() { + mViewModel = ViewModelProviders.of(this, mViewModelFactory).get(DoxsViewModel.class); mViewModel.setOxmListener(this); @@ -157,11 +265,10 @@ public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewM mViewModel.getConnectWifiEasySetupResponse().observe(this, this::processConnectWifiEasySetupResponse); if (getActivity() != null) { - mSharedViewModel = ViewModelProviders.of(getActivity(), getViewModelFactory()).get(SharedViewModel.class); + mSharedViewModel = ViewModelProviders.of(getActivity(), mViewModelFactory).get(SharedViewModel.class); } } - @Override public void onSwipeRefresh() { mAdapter.clearItems(); mViewModel.onScanRequested(); @@ -222,6 +329,8 @@ public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewM case SCAN_DEVICES: Toast.makeText(getActivity(), R.string.devices_error_scanning_devices, Toast.LENGTH_SHORT).show(); break; + case PAIRWISE_DEVICES: + Toast.makeText(getActivity(), R.string.devices_error_pairing_devices, Toast.LENGTH_SHORT).show(); default: break; } @@ -380,10 +489,9 @@ public class DoxsFragment extends RecyclerWithSwipeFragment implements DoxsViewM } } - private void launchGenericClientView(String ipAddress, String deviceId) { + private void launchGenericClientView(String deviceId) { Intent intent = new Intent(getActivity(), GenericClientActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra("IpAddress", ipAddress); intent.putExtra("DeviceId", deviceId); startActivity(intent); } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsListAdapter.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsListAdapter.java index 009b0e549d1ddca381042f750d331d8c583532cb..90b632e357170ede01f56357b01863253b86b090 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsListAdapter.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/DoxsListAdapter.java @@ -23,11 +23,13 @@ package org.openconnectivity.otgc.devicelist.presentation.view; import android.content.Context; import android.graphics.Rect; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v7.util.SortedList; -import android.support.v7.widget.PopupMenu; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.selection.ItemDetailsLookup; +import androidx.recyclerview.selection.SelectionTracker; +import androidx.recyclerview.widget.SortedList; +import androidx.appcompat.widget.PopupMenu; +import androidx.recyclerview.widget.RecyclerView; import android.text.TextUtils; import android.view.LayoutInflater; import android.view.MenuItem; @@ -40,6 +42,7 @@ import android.widget.TextView; import org.openconnectivity.otgc.R; import org.openconnectivity.otgc.devicelist.domain.model.Device; import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; +import org.openconnectivity.otgc.devicelist.domain.model.Role; import butterknife.BindView; import butterknife.ButterKnife; @@ -47,18 +50,21 @@ import butterknife.ButterKnife; public class DoxsListAdapter extends RecyclerView.Adapter { SortedList mDataset; private Context mContext; + private SelectionTracker mSelectionTracker; private static MyClickListener sMyClickListener; private static MyMenuItemClickListener sMyMenuItemClickListener; // Provide a reference to the views for each data item // Complex data items may need more than one view per item, and // you provide access to all the views for a data item in a view holder - public static class DoxsListViewHolder extends RecyclerView.ViewHolder - implements View.OnClickListener, PopupMenu.OnMenuItemClickListener { + public class DoxsListViewHolder extends RecyclerView.ViewHolder + implements View.OnClickListener, PopupMenu.OnMenuItemClickListener, ViewHolderWithDetails { // each data item is just a string in this case + @BindView(R.id.card_view) View mView; @BindView(R.id.line_device_type) View mLineDeviceType; @BindView(R.id.text_device_name) TextView mDeviceName; @BindView(R.id.text_device_uuid) TextView mDeviceUuid; + @BindView(R.id.text_device_role) TextView mDeviceRole; @BindView(R.id.text_device_type) TextView mDeviceType; //@BindView(R.id.img_btn_bottom_right) ImageButton mImageButton; @BindView(R.id.img_btn_popup_menu) ImageButton mPopupButton; @@ -105,6 +111,15 @@ public class DoxsListAdapter extends RecyclerView.Adapter { PopupMenu popupMenu = new PopupMenu(mContext, holder.mPopupButton); popupMenu.inflate(R.menu.menu_owned_devices); popupMenu.setOnMenuItemClickListener(holder); - if (mDataset.get(position).getType().equals(DeviceType.OWNED_BY_OTHER)) { + if (device.getType().equals(DeviceType.OWNED_BY_OTHER)) { popupMenu.getMenu().findItem(R.id.menu_item_set_device_name).setVisible(false); } @@ -213,7 +241,7 @@ public class DoxsListAdapter extends RecyclerView.Adapter itemList; + + public MyItemKeyProvider(int scope, SortedList itemList) { + super(scope); + this.itemList = itemList; + } + + @Nullable + @Override + public Object getKey(int position) { + return itemList.get(position); + } + + @Override + public int getPosition(@NonNull Object key) { + return itemList.indexOf((Device)key); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/MyItemLookup.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/MyItemLookup.java new file mode 100644 index 0000000000000000000000000000000000000000..c84e7801c7f1edab950a53893a791bd79c7dd710 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/MyItemLookup.java @@ -0,0 +1,53 @@ +/* + * ***************************************************************** + * + * Copyright 2018 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.devicelist.presentation.view; + +import android.view.MotionEvent; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.selection.ItemDetailsLookup; +import androidx.recyclerview.widget.RecyclerView; + +public class MyItemLookup extends ItemDetailsLookup { + private final RecyclerView recyclerView; + + public MyItemLookup(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + } + + @Nullable + @Override + public ItemDetails getItemDetails(@NonNull MotionEvent e) { + View view = recyclerView.findChildViewUnder(e.getX(), e.getY()); + if (view != null) { + RecyclerView.ViewHolder viewHolder = recyclerView.getChildViewHolder(view); + if (viewHolder instanceof DoxsListAdapter.DoxsListViewHolder) { + return ((DoxsListAdapter.DoxsListViewHolder) viewHolder).getItemDetails(); + } + } + + return null; + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/ViewHolderWithDetails.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/ViewHolderWithDetails.java new file mode 100644 index 0000000000000000000000000000000000000000..1da9846ffee79c3a0bed2ff8a60d770a89a02778 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/view/ViewHolderWithDetails.java @@ -0,0 +1,29 @@ +/* + * ***************************************************************** + * + * Copyright 2018 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.devicelist.presentation.view; + +import androidx.recyclerview.selection.ItemDetailsLookup; + +public interface ViewHolderWithDetails { + ItemDetailsLookup.ItemDetails getItemDetails(); +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DeviceListViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DeviceListViewModel.java index 8ceb127024f7a00b2d80087e05af44206ff81510..b20166e8df39b579125c8f323b96a63fe3ab99c2 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DeviceListViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DeviceListViewModel.java @@ -21,9 +21,9 @@ */ package org.openconnectivity.otgc.devicelist.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; import org.iotivity.base.OcProvisioning; import org.openconnectivity.otgc.common.domain.model.NetworkDisconnectedException; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DoxsViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DoxsViewModel.java index c272e87b6fd01b9839137d0b9d8f331d5f442529..07f2fdba009c17455054531e61bc45968586630a 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DoxsViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/DoxsViewModel.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.devicelist.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import org.iotivity.base.OcSecureResource; import org.iotivity.base.OxmType; @@ -36,15 +36,18 @@ import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelError; import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelErrorType; import org.openconnectivity.otgc.devicelist.domain.model.DeviceType; import org.openconnectivity.otgc.common.domain.usecase.GetDeviceNameUseCase; +import org.openconnectivity.otgc.devicelist.domain.usecase.GetDeviceRoleUseCase; import org.openconnectivity.otgc.devicelist.domain.usecase.GetOTMethodsUseCase; import org.openconnectivity.otgc.devicelist.domain.usecase.OnboardUseCase; import org.openconnectivity.otgc.devicelist.domain.model.Device; import org.openconnectivity.otgc.common.presentation.viewmodel.Response; import org.openconnectivity.otgc.devicelist.domain.usecase.OffboardUseCase; +import org.openconnectivity.otgc.devicelist.domain.usecase.PairwiseDevicesUseCase; import org.openconnectivity.otgc.devicelist.domain.usecase.ScanDevicesUseCase; import org.openconnectivity.otgc.devicelist.domain.usecase.SetDeviceNameUseCase; import org.openconnectivity.otgc.devicelist.domain.usecase.SetOTMethodUseCase; import org.openconnectivity.otgc.common.domain.rx.SchedulersFacade; +import org.openconnectivity.otgc.devicelist.domain.usecase.UnlinkDevicesUseCase; import org.openconnectivity.otgc.devicelist.domain.usecase.WiFiEasySetupUseCase; import org.openconnectivity.otgc.wlanscan.domain.model.WifiNetwork; import org.openconnectivity.otgc.wlanscan.domain.usecase.RegisterScanResultsReceiverUseCase; @@ -67,6 +70,9 @@ public class DoxsViewModel extends BaseViewModel { private final GetDeviceNameUseCase mGetDeviceNameUseCase; private final ScanWiFiNetworksUseCase mScanWiFiNetworksUseCase; private final WiFiEasySetupUseCase mWiFiEasySetupUseCase; + private final GetDeviceRoleUseCase mGetDeviceRoleUseCase; + private final PairwiseDevicesUseCase mPairwiseDevicesUseCase; + private final UnlinkDevicesUseCase mUnlinkDevicesUseCase; private final SchedulersFacade mSchedulersFacade; @@ -92,6 +98,9 @@ public class DoxsViewModel extends BaseViewModel { GetDeviceNameUseCase getDeviceNameUseCase, ScanWiFiNetworksUseCase scanWiFiNetworksUseCase, WiFiEasySetupUseCase wiFiEasySetupUseCase, + GetDeviceRoleUseCase getDeviceRoleUseCase, + PairwiseDevicesUseCase pairwiseDevicesUseCase, + UnlinkDevicesUseCase unlinkDevicesUseCase, SchedulersFacade schedulersFacade) { this.mCheckConnectionUseCase = checkConnectionUseCase; this.mScanDevicesUseCase = scanDevicesUseCase; @@ -104,6 +113,9 @@ public class DoxsViewModel extends BaseViewModel { this.mGetDeviceNameUseCase = getDeviceNameUseCase; this.mScanWiFiNetworksUseCase = scanWiFiNetworksUseCase; this.mWiFiEasySetupUseCase = wiFiEasySetupUseCase; + this.mGetDeviceRoleUseCase = getDeviceRoleUseCase; + this.mPairwiseDevicesUseCase = pairwiseDevicesUseCase; + this.mUnlinkDevicesUseCase = unlinkDevicesUseCase; this.mSchedulersFacade = schedulersFacade; @@ -146,8 +158,12 @@ public class DoxsViewModel extends BaseViewModel { .map(device -> { device.setDeviceInfo(mGetDeviceInfoUseCase.execute(device.getDeviceId()).blockingGet()); return device; - }) - .map(device -> { + }).map(device -> { + device.setRole( + mGetDeviceRoleUseCase.execute(device.getDeviceId()).blockingGet()); + + return device; + }).map(device -> { if (device.getType().equals(DeviceType.OWNED_BY_SELF)) { String storedDeviceName = mGetDeviceNameUseCase.execute(device.getDeviceId()).blockingGet(); if (storedDeviceName != null && !storedDeviceName.isEmpty()) { @@ -191,6 +207,12 @@ public class DoxsViewModel extends BaseViewModel { device.setDeviceInfo(mGetDeviceInfoUseCase.execute(device.getDeviceId()).blockingGet()); return device; })) + .map(device -> { + device.setRole( + mGetDeviceRoleUseCase.execute(device.getDeviceId()).blockingGet()); + + return device; + }) .subscribeOn(mSchedulersFacade.io()) .observeOn(mSchedulersFacade.ui()) .doOnSubscribe(__ -> otmResponse.setValue(Response.loading())) @@ -263,11 +285,37 @@ public class DoxsViewModel extends BaseViewModel { ); } + public void pairwiseDevices(String serverId, String clientId) { + mDisposables.add(mPairwiseDevicesUseCase.execute(serverId, clientId) + .subscribeOn(mSchedulersFacade.io()) + .observeOn(mSchedulersFacade.ui()) + .doOnSubscribe(__ -> mProcessing.setValue(true)) + .doFinally(() -> mProcessing.setValue(false)) + .subscribe( + () -> {}, + throwable -> mError.setValue(new ViewModelError(Error.PAIRWISE_DEVICES, null)) + )); + } + + public void unlinkDevices(String serverId, String clientId) { + mDisposables.add(mUnlinkDevicesUseCase.execute(serverId, clientId) + .subscribeOn(mSchedulersFacade.io()) + .observeOn(mSchedulersFacade.ui()) + .doOnSubscribe(__ -> mProcessing.setValue(true)) + .doFinally(() -> mProcessing.setValue(false)) + .subscribe( + () -> {}, + throwable -> mError.setValue(new ViewModelError(Error.UNLINK_DEVICES, null)) + )); + } + public interface SelectOxMListener { OxmType onGetOxM(List supportedOxm); } public enum Error implements ViewModelErrorType { - SCAN_DEVICES + SCAN_DEVICES, + PAIRWISE_DEVICES, + UNLINK_DEVICES } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/SharedViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/SharedViewModel.java index 7085892e2a4dbcece0a4883db572eaa5c8d8bc5b..ad747d85d55d600a998a147f4ec231fded73f7f4 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/SharedViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/devicelist/presentation/viewmodel/SharedViewModel.java @@ -21,10 +21,10 @@ */ package org.openconnectivity.otgc.devicelist.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; -import android.support.annotation.NonNull; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; +import androidx.annotation.NonNull; import javax.inject.Inject; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/di/AppInjector.java b/otgc/src/main/java/org/openconnectivity/otgc/di/AppInjector.java index 27a5f40c9911c0db1c8bb3389d84471643d14d37..613308f33ae8e6ad116ed3086e3374a7692a73f2 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/di/AppInjector.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/di/AppInjector.java @@ -25,9 +25,9 @@ package org.openconnectivity.otgc.di; import android.app.Activity; import android.app.Application; import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.fragment.app.FragmentManager; import org.openconnectivity.otgc.App; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/di/AppModule.java b/otgc/src/main/java/org/openconnectivity/otgc/di/AppModule.java index bf1faa671e9719f6b2005d639d7b0bc616924445..005bf963e3cbe31205c37afa07c7896b49afc916 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/di/AppModule.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/di/AppModule.java @@ -20,7 +20,7 @@ package org.openconnectivity.otgc.di; import android.app.Application; -import android.arch.persistence.room.Room; +import androidx.room.Room; import android.content.Context; import org.openconnectivity.otgc.common.data.persistence.dao.DeviceDao; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/di/BuildersModule.java b/otgc/src/main/java/org/openconnectivity/otgc/di/BuildersModule.java index cef9a131c8d9aa5bb7332657cfeb6d875ffd637d..5ff8f4d22acdca4284f0adf59c5421af29210940 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/di/BuildersModule.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/di/BuildersModule.java @@ -27,6 +27,7 @@ import org.openconnectivity.otgc.credential.presentation.view.CredActivity; import org.openconnectivity.otgc.credential.presentation.view.CredentialsActivity; import org.openconnectivity.otgc.devicelist.DeviceListBuildersModule; import org.openconnectivity.otgc.devicelist.presentation.view.DeviceListActivity; +import org.openconnectivity.otgc.linkedroles.presentation.view.LinkedRolesActivity; import org.openconnectivity.otgc.login.presentation.view.LoginActivity; import org.openconnectivity.otgc.splash.presentation.view.SplashActivity; import org.openconnectivity.otgc.wlanscan.presentation.view.WlanScanActivity; @@ -63,4 +64,7 @@ public interface BuildersModule { @ContributesAndroidInjector(modules = ClientBuildersModule.class) abstract GenericClientActivity bindGenericClientActivity(); + + @ContributesAndroidInjector + abstract LinkedRolesActivity bindLinkedRolesActivity(); } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelKey.java b/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelKey.java index 31c22aa877ab84480738c01b6f7fa16073bc8e29..b5d269a274b0a8ff8577edd0e9346b8070440833 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelKey.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelKey.java @@ -22,7 +22,7 @@ package org.openconnectivity.otgc.di; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.ViewModel; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelModule.java b/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelModule.java index 1624b14575412e5e97c5ce947eda8e1e088dbd09..53252775bd4419d558e4d463ef668e19dfdb3604 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelModule.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/di/ViewModelModule.java @@ -22,8 +22,8 @@ package org.openconnectivity.otgc.di; -import android.arch.lifecycle.ViewModel; -import android.arch.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModel; +import androidx.lifecycle.ViewModelProvider; import org.openconnectivity.otgc.accesscontrol.presentation.viewmodel.AccessControlViewModel; import org.openconnectivity.otgc.accesscontrol.presentation.viewmodel.AceViewModel; @@ -35,6 +35,7 @@ import org.openconnectivity.otgc.credential.presentation.viewmodel.CredentialsVi import org.openconnectivity.otgc.devicelist.presentation.viewmodel.DeviceListViewModel; import org.openconnectivity.otgc.devicelist.presentation.viewmodel.SharedViewModel; import org.openconnectivity.otgc.devicelist.presentation.viewmodel.DoxsViewModel; +import org.openconnectivity.otgc.linkedroles.presentation.viewmodel.LinkedRolesViewModel; import org.openconnectivity.otgc.login.presentation.viewmodel.LoginViewModel; import org.openconnectivity.otgc.splash.presentation.viewmodel.SplashViewModel; import org.openconnectivity.otgc.wlanscan.presentation.viewmodel.WlanScanViewModel; @@ -100,6 +101,11 @@ abstract class ViewModelModule { @ViewModelKey(GenericClientViewModel.class) abstract ViewModel bindGenericClientViewModel(GenericClientViewModel genericClientViewModel); + @Binds + @IntoMap + @ViewModelKey(LinkedRolesViewModel.class) + abstract ViewModel bindLinkedRolesViewModel(LinkedRolesViewModel linkedRolesViewModel); + @Binds @IntoMap @ViewModelKey(ResourceViewModel.class) diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/LinkRolesForClientUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/LinkRolesForClientUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..2102eb34b50c781ab65a4b49e7de3f62b3b94662 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/LinkRolesForClientUseCase.java @@ -0,0 +1,47 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.domain.usecase; + +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; +import org.openconnectivity.otgc.credential.data.repository.CmsRepository; + +import javax.inject.Inject; + +import io.reactivex.Completable; + +public class LinkRolesForClientUseCase { + private final IotivityRepository mIotivityRepository; + private final CmsRepository mCmsRepository; + + @Inject + public LinkRolesForClientUseCase(IotivityRepository iotivityRepository, + CmsRepository cmsRepository) { + this.mIotivityRepository = iotivityRepository; + this.mCmsRepository = cmsRepository; + } + + public Completable execute(String deviceId, String roleId, String roleAuthority) { + return mIotivityRepository.findOcSecureResource(deviceId) + .flatMapCompletable(ocSecureResource -> mCmsRepository.provisionRoleCertificate(ocSecureResource, roleId, roleAuthority)); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/LinkRolesForServerUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/LinkRolesForServerUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..8c0f982b9dda82df68ddb91b21563a5223a6e271 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/LinkRolesForServerUseCase.java @@ -0,0 +1,67 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.domain.usecase; + +import org.iotivity.base.AceSubjectRole; +import org.iotivity.base.AceSubjectType; +import org.iotivity.base.OicSecAce; +import org.iotivity.base.OicSecAceSubject; +import org.openconnectivity.otgc.accesscontrol.data.repository.AmsRepository; +import org.openconnectivity.otgc.client.data.repository.ResourceRepository; +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; + +import java.util.ArrayList; + +import javax.inject.Inject; + +import io.reactivex.Completable; + +public class LinkRolesForServerUseCase { + private final IotivityRepository mIotivityRepository; + private final AmsRepository mAmsRepository; + private final ResourceRepository mResourceRepository; + + @Inject + public LinkRolesForServerUseCase(IotivityRepository iotivityRepository, + AmsRepository amsRepository, + ResourceRepository resourceRepository) { + this.mIotivityRepository = iotivityRepository; + this.mAmsRepository = amsRepository; + this.mResourceRepository = resourceRepository; + } + + public Completable execute(String deviceId, String roleId, String roleAuthority) { + return mIotivityRepository.getDeviceCoapIpv6Host(deviceId) + .flatMap(mIotivityRepository::findResources) + .map(mResourceRepository::getVerticalResources) + .flatMapCompletable(resources -> mIotivityRepository.findOcSecureResource(deviceId) + .flatMapCompletable(ocSecureResource -> { + AceSubjectRole role = new AceSubjectRole(roleId, roleAuthority); + OicSecAceSubject subject = new OicSecAceSubject(AceSubjectType.SUBJECT_ROLE.getValue(), null, role, null); + + OicSecAce ace = new OicSecAce(0, subject, 31, resources, new ArrayList<>()); + return mAmsRepository.provisionAcl(ocSecureResource, ace); + }) + ); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/RetrieveLinkedRolesForClientUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/RetrieveLinkedRolesForClientUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..26403529c8107eb75a049bf052fd0b81ccceb990 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/RetrieveLinkedRolesForClientUseCase.java @@ -0,0 +1,62 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.domain.usecase; + +import org.iotivity.base.OicSecCred; +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; +import org.openconnectivity.otgc.credential.data.repository.CmsRepository; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import io.reactivex.Single; + +public class RetrieveLinkedRolesForClientUseCase { + private final IotivityRepository mIotivityRepository; + private final CmsRepository mCmsRepository; + + @Inject + public RetrieveLinkedRolesForClientUseCase(IotivityRepository iotivityRepository, + CmsRepository cmsRepository) { + this.mIotivityRepository = iotivityRepository; + this.mCmsRepository = cmsRepository; + } + + public Single> execute(String deviceId) { + return mIotivityRepository.findOcSecureResource(deviceId) + .flatMap(mCmsRepository::getCredentials) + .map(credentials -> { + List roles = new ArrayList<>(); + + for (OicSecCred cred : credentials.getOicSecCreds()) { + if (cred.getRole() != null) { + roles.add(cred.getRole().getId()); + } + } + + return roles; + }); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/RetrieveLinkedRolesForServerUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/RetrieveLinkedRolesForServerUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..c78b57ab6c48ac03e2645341418705a4ad8624d2 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/RetrieveLinkedRolesForServerUseCase.java @@ -0,0 +1,62 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.domain.usecase; + +import org.iotivity.base.OicSecAce; +import org.openconnectivity.otgc.accesscontrol.data.repository.AmsRepository; +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import io.reactivex.Single; + +public class RetrieveLinkedRolesForServerUseCase { + private final IotivityRepository mIotivityRepository; + private final AmsRepository mAmsRepository; + + @Inject + public RetrieveLinkedRolesForServerUseCase(IotivityRepository iotivityRepository, + AmsRepository amsRepository) { + this.mIotivityRepository = iotivityRepository; + this.mAmsRepository = amsRepository; + } + + public Single> execute(String deviceId) { + return mIotivityRepository.findOcSecureResource(deviceId) + .flatMap(mAmsRepository::getAcl) + .map(acl -> { + List roles = new ArrayList<>(); + + for(OicSecAce ace : acl.getOicSecAces()) { + if (ace.getSubject().getRole() != null) { + roles.add(ace.getSubject().getRole().getId()); + } + } + + return roles; + }); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/UnlinkRoleForClientUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/UnlinkRoleForClientUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..7be3217821a82955773eb9c7d3bb85cf40e07833 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/UnlinkRoleForClientUseCase.java @@ -0,0 +1,62 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.domain.usecase; + +import org.iotivity.base.OicSecCred; +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; +import org.openconnectivity.otgc.credential.data.repository.CmsRepository; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import io.reactivex.Completable; + +public class UnlinkRoleForClientUseCase { + private final IotivityRepository mIotivityRepository; + private final CmsRepository mCmsRepository; + + @Inject + public UnlinkRoleForClientUseCase(IotivityRepository iotivityRepository, + CmsRepository cmsRepository) { + this.mIotivityRepository = iotivityRepository; + this.mCmsRepository = cmsRepository; + } + + public Completable execute(String deviceId, String roleId) { + return mIotivityRepository.findOcSecureResource(deviceId) + .flatMapCompletable(ocSecureResource -> mCmsRepository.getCredentials(ocSecureResource) + .flatMapCompletable(oicSecCreds -> { + List deleteCredList = new ArrayList<>(); + for (OicSecCred cred : oicSecCreds.getOicSecCreds()) { + if (cred.getRole() != null && cred.getRole().getId().equals(roleId)) { + deleteCredList.add(mCmsRepository.deleteCredential(ocSecureResource, cred.getCredID())); + } + } + + return Completable.merge(deleteCredList); + }) + ); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/UnlinkRoleForServerUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/UnlinkRoleForServerUseCase.java new file mode 100644 index 0000000000000000000000000000000000000000..4941bf06c419bccaa77e265d59870ef818633772 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/domain/usecase/UnlinkRoleForServerUseCase.java @@ -0,0 +1,63 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.domain.usecase; + +import org.iotivity.base.OicSecAce; +import org.openconnectivity.otgc.accesscontrol.data.repository.AmsRepository; +import org.openconnectivity.otgc.common.data.repository.IotivityRepository; + +import java.util.ArrayList; +import java.util.List; + +import javax.inject.Inject; + +import io.reactivex.Completable; + +public class UnlinkRoleForServerUseCase { + private final IotivityRepository mIotivityRepository; + private final AmsRepository mAmsRepository; + + @Inject + public UnlinkRoleForServerUseCase(IotivityRepository iotivityRepository, + AmsRepository amsRepository) { + this.mIotivityRepository = iotivityRepository; + this.mAmsRepository = amsRepository; + } + + public Completable execute(String deviceId, String roleId) { + return mIotivityRepository.findOcSecureResource(deviceId) + .flatMapCompletable(ocSecureResource -> mAmsRepository.getAcl(ocSecureResource) + .flatMapCompletable(oicSecAcl -> { + List deleteAceList = new ArrayList<>(); + for (OicSecAce ace : oicSecAcl.getOicSecAces()) { + if (ace.getSubject().getRole() != null && ace.getSubject().getRole().getId().equals(roleId)) { + deleteAceList.add(mAmsRepository.deleteAcl(ocSecureResource, ace.getAceID())); + } + } + + return Completable.merge(deleteAceList); + }) + ); + + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/view/LinkedRolesActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/view/LinkedRolesActivity.java new file mode 100644 index 0000000000000000000000000000000000000000..c1ee556e3341bc09e1d24d4fbdb0e5a90a97bcf3 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/view/LinkedRolesActivity.java @@ -0,0 +1,199 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.presentation.view; + +import android.content.Intent; +import android.os.Bundle; +import android.view.ContextThemeWrapper; +import android.view.MenuItem; +import android.view.View; +import android.widget.EditText; +import android.widget.LinearLayout; +import android.widget.ProgressBar; +import android.widget.Toast; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; + +import org.openconnectivity.otgc.R; +import org.openconnectivity.otgc.common.presentation.view.EmptyRecyclerView; +import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelError; +import org.openconnectivity.otgc.devicelist.domain.model.Role; +import org.openconnectivity.otgc.di.Injectable; +import org.openconnectivity.otgc.linkedroles.presentation.viewmodel.LinkedRolesViewModel; + +import javax.inject.Inject; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import butterknife.BindView; +import butterknife.ButterKnife; +import butterknife.OnClick; +import timber.log.Timber; + +public class LinkedRolesActivity extends AppCompatActivity implements Injectable { + @Inject + ViewModelProvider.Factory mViewModelFactory; + + @BindView(R.id.progress_bar) ProgressBar mProgressBar; + @BindView(R.id.toolbar) Toolbar mToolbar; + @BindView(R.id.recycler_ocf_roles) EmptyRecyclerView mRecyclerView; + @BindView(R.id.floating_button_roles_add) FloatingActionButton mFloatingActionButton; + + @OnClick(R.id.floating_button_roles_add) + protected void onAddPressed() { + AlertDialog.Builder alertDialog = new AlertDialog.Builder(new ContextThemeWrapper(LinkedRolesActivity.this, R.style.AppTheme)); + alertDialog.setTitle(LinkedRolesActivity.this.getString(R.string.linked_roles_dialog_add_role_title)); + + LinearLayout layout = new LinearLayout(LinkedRolesActivity.this); + layout.setOrientation(LinearLayout.VERTICAL); + final EditText etRoleIdInput = new EditText(LinkedRolesActivity.this); + etRoleIdInput.setHint(R.string.linked_roles_dialog_role_id_hint); + final EditText etRoleAuthorityInput = new EditText(LinkedRolesActivity.this); + etRoleAuthorityInput.setHint(R.string.linked_roles_dialog_role_authority_hint); + layout.addView(etRoleIdInput); + layout.addView(etRoleAuthorityInput); + layout.setPadding(50, 40, 50, 10); + + alertDialog.setView(layout); + alertDialog.setPositiveButton(LinkedRolesActivity.this.getString(R.string.linked_roles_dialog_add_role_yes_option), (dialog, which) -> { + dialog.dismiss(); + if (!etRoleIdInput.getText().toString().isEmpty()) { + mViewModel.addLinkedRole(mDeviceId, mDeviceRole, etRoleIdInput.getText().toString(), etRoleAuthorityInput.getText().toString()); + } else { + Timber.d("Fiil role ID input text"); + } + }); + alertDialog.setNegativeButton(LinkedRolesActivity.this.getString(R.string.linked_roles_dialog_add_role_no_option), (dialog, which) -> dialog.dismiss()).show(); + } + + private LinkedRolesViewModel mViewModel; + private LinkedRolesAdapter mAdapter; + + private String mDeviceId; + private Role mDeviceRole; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_linked_roles); + + ButterKnife.bind(this); + initViews(); + initViewModel(); + + Intent intent = getIntent(); + mDeviceId = intent.getStringExtra("deviceId"); + mDeviceRole = Role.valueOf(intent.getStringExtra("deviceRole")); + } + + @Override + protected void onResume() { + super.onResume(); + mViewModel.retrieveLinkedRoles(mDeviceId, mDeviceRole); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + int id = item.getItemId(); + if (id == android.R.id.home) { + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void initViews() { + setSupportActionBar(mToolbar); + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); + } + + mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); + mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(RecyclerView view, int dx, int dy) { + super.onScrolled(view, dx, dy); + if (dy > 0 && mFloatingActionButton.getVisibility() == View.VISIBLE) { + mFloatingActionButton.hide(); + } else if (dy < 0 && mFloatingActionButton.getVisibility() != View.VISIBLE) { + mFloatingActionButton.show(); + } + } + }); + + mAdapter = new LinkedRolesAdapter(this); + LinkedRolesAdapter.setOnDeleteClickListener((position, v) -> + mViewModel.deleteLinkedRole(mDeviceId, mDeviceRole, mAdapter.mDataset.get(position)) + ); + + mRecyclerView.setAdapter(mAdapter); + } + + private void initViewModel() { + mViewModel = ViewModelProviders.of(this, mViewModelFactory).get(LinkedRolesViewModel.class); + + mViewModel.isProcessing().observe(this, this::handleProcessing); + mViewModel.getError().observe(this, this::handleError); + + mViewModel.getLinkedRoles().observe(this, this::processLinkedRoles); + mViewModel.getDeletedRoleId().observe(this, this::processDeletedRoleId); + } + + private void handleProcessing(@NonNull Boolean isProcessing) { + mProgressBar.setVisibility(isProcessing ? View.VISIBLE : View.GONE); + } + + private void handleError(@NonNull ViewModelError error) { + int errorId = 0; + switch ((LinkedRolesViewModel.Error)error.getType()) { + case RETRIEVE: + errorId = R.string.linked_roles_error_retrieve; + break; + case DELETE: + default: + break; + } + + if (errorId != 0) { + Toast.makeText(this, errorId, Toast.LENGTH_SHORT).show(); + } + } + + private void processLinkedRoles(@NonNull String role) { + mAdapter.addItem(role); + } + + private void processDeletedRoleId(@NonNull String roleId) { + mAdapter.deleteItemById(roleId); + } + +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/view/LinkedRolesAdapter.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/view/LinkedRolesAdapter.java new file mode 100644 index 0000000000000000000000000000000000000000..5bb1c42c7738b1c4797759f4fd39bb3650e65863 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/view/LinkedRolesAdapter.java @@ -0,0 +1,157 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.presentation.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.TextView; + +import org.openconnectivity.otgc.R; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SortedList; +import butterknife.BindView; +import butterknife.ButterKnife; + +public class LinkedRolesAdapter extends RecyclerView.Adapter { + SortedList mDataset; + private static LinkedRolesAdapter.DeleteClickListener sDeleteClickListener; + + public static class LinkedRolesViewHolder extends RecyclerView.ViewHolder + implements View.OnClickListener { + @BindView(R.id.text_role_id) TextView mRoleId; + @BindView(R.id.img_btn_delete_role) ImageButton mDeleteButton; + + private LinkedRolesViewHolder(View itemView) { + super(itemView); + ButterKnife.bind(this, itemView); + + mDeleteButton.setOnClickListener(this); + } + + @Override + public void onClick(View v) { + sDeleteClickListener.onDeleteClick(getAdapterPosition(), v); + } + } + + LinkedRolesAdapter(Context context) { + mDataset = new SortedList<>(String.class, new SortedList.Callback() { + @Override + public int compare(String a1, String a2) { + return a1.compareTo(a2); + } + + @Override + public void onChanged(int position, int count) { + notifyItemRangeChanged(position, count); + } + + @Override + public boolean areContentsTheSame(String oldItem, String newItem) { + // TODO: Improve + return oldItem.equals(newItem); + } + + @Override + public boolean areItemsTheSame(String item1, String item2) { + return item1.equals(item2); + } + + @Override + public void onInserted(int position, int count) { + notifyItemRangeInserted(position, count); + } + + @Override + public void onRemoved(int position, int count) { + notifyItemRangeRemoved(position, count); + } + + @Override + public void onMoved(int fromPosition, int toPosition) { + notifyItemMoved(fromPosition, toPosition); + } + }); + } + + public static void setOnDeleteClickListener(LinkedRolesAdapter.DeleteClickListener deleteClickListener) { + sDeleteClickListener = deleteClickListener; + } + + // Create new views (invoked by the layout manager) + @Override + @NonNull + public LinkedRolesAdapter.LinkedRolesViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + // Create a new view + View v = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_role, parent, false); + + return new LinkedRolesAdapter.LinkedRolesViewHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull LinkedRolesViewHolder holder, int position) { + String role = mDataset.get(position); + + if (role != null) { + holder.mRoleId.setText(role); + } + } + + @Override + public int getItemCount() { + return mDataset != null ? mDataset.size() : 0; + } + + public void clearItems() { + mDataset.beginBatchedUpdates(); + while (mDataset.size() > 0) { + mDataset.removeItemAt(mDataset.size() - 1); + } + mDataset.endBatchedUpdates(); + } + + public void addItem(String item) { + if (item != null) { + mDataset.add(item); + } + } + + public void deleteItemById(String roleId) { + for (int i = 0; i < mDataset.size(); i++) { + if (mDataset.get(i).equals(roleId)) { + mDataset.removeItemAt(i); + break; + } + } + } + + public interface DeleteClickListener { + void onDeleteClick(int position, View v); + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/viewmodel/LinkedRolesViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/viewmodel/LinkedRolesViewModel.java new file mode 100644 index 0000000000000000000000000000000000000000..8d1901dbc5f4cacde2a5c7b8db0406a23ae01252 --- /dev/null +++ b/otgc/src/main/java/org/openconnectivity/otgc/linkedroles/presentation/viewmodel/LinkedRolesViewModel.java @@ -0,0 +1,172 @@ +/* + * ***************************************************************** + * + * Copyright 2019 DEKRA Testing and Certification, S.A.U. All Rights Reserved. + * + * ****************************************************************** + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * ****************************************************************** + */ + +package org.openconnectivity.otgc.linkedroles.presentation.viewmodel; + +import org.openconnectivity.otgc.accesscontrol.presentation.viewmodel.AccessControlViewModel; +import org.openconnectivity.otgc.common.domain.rx.SchedulersFacade; +import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelError; +import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelErrorType; +import org.openconnectivity.otgc.devicelist.domain.model.Role; +import org.openconnectivity.otgc.linkedroles.domain.usecase.LinkRolesForClientUseCase; +import org.openconnectivity.otgc.linkedroles.domain.usecase.LinkRolesForServerUseCase; +import org.openconnectivity.otgc.linkedroles.domain.usecase.RetrieveLinkedRolesForClientUseCase; +import org.openconnectivity.otgc.linkedroles.domain.usecase.RetrieveLinkedRolesForServerUseCase; +import org.openconnectivity.otgc.linkedroles.domain.usecase.UnlinkRoleForClientUseCase; +import org.openconnectivity.otgc.linkedroles.domain.usecase.UnlinkRoleForServerUseCase; + +import java.util.List; + +import javax.inject.Inject; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; +import io.reactivex.Completable; +import io.reactivex.Single; +import io.reactivex.disposables.CompositeDisposable; + +public class LinkedRolesViewModel extends ViewModel { + + private final RetrieveLinkedRolesForClientUseCase mRetrieveRolesForClientUseCase; + private final RetrieveLinkedRolesForServerUseCase mRetrieveRolesForServerUseCase; + private final LinkRolesForClientUseCase mLinkRolesForClientUseCase; + private final LinkRolesForServerUseCase mLinkRolesForServerUseCase; + private final UnlinkRoleForClientUseCase mUnlinkRoleForClientUseCase; + private final UnlinkRoleForServerUseCase mUnlinkRoleForServerUseCase; + + private final SchedulersFacade mSchedulersFacade; + private final CompositeDisposable mDisposables = new CompositeDisposable(); + + private final MutableLiveData mProcessing = new MutableLiveData<>(); + private final MutableLiveData mError = new MutableLiveData<>(); + + private final MutableLiveData mLinkedRoles = new MutableLiveData<>(); + private final MutableLiveData mDeletedRoleId = new MutableLiveData<>(); + + @Inject + LinkedRolesViewModel(SchedulersFacade schedulersFacade, + RetrieveLinkedRolesForClientUseCase retrieveLinkedRolesForClientUseCase, + RetrieveLinkedRolesForServerUseCase retrieveLinkedRolesForServerUseCase, + LinkRolesForClientUseCase linkRolesForClientUseCase, + LinkRolesForServerUseCase linkRolesForServerUseCase, + UnlinkRoleForClientUseCase unlinkRoleForClientUseCase, + UnlinkRoleForServerUseCase unlinkRoleForServerUseCase) { + this.mSchedulersFacade = schedulersFacade; + + this.mRetrieveRolesForClientUseCase = retrieveLinkedRolesForClientUseCase; + this.mRetrieveRolesForServerUseCase = retrieveLinkedRolesForServerUseCase; + this.mLinkRolesForClientUseCase = linkRolesForClientUseCase; + this.mLinkRolesForServerUseCase = linkRolesForServerUseCase; + this.mUnlinkRoleForClientUseCase = unlinkRoleForClientUseCase; + this.mUnlinkRoleForServerUseCase = unlinkRoleForServerUseCase; + } + + @Override + protected void onCleared() { + mDisposables.clear(); + } + + public LiveData isProcessing() { + return mProcessing; + } + + public LiveData getError() { + return mError; + } + + public LiveData getLinkedRoles() { + return mLinkedRoles; + } + + public LiveData getDeletedRoleId() { + return mDeletedRoleId; + } + + + public void retrieveLinkedRoles(String deviceId, Role deviceRole) { + Single> useCase; + + if (deviceRole.equals(Role.CLIENT)) { + useCase = mRetrieveRolesForClientUseCase.execute(deviceId); + } else { + useCase = mRetrieveRolesForServerUseCase.execute(deviceId); + } + mDisposables.add(useCase + .subscribeOn(mSchedulersFacade.io()) + .observeOn(mSchedulersFacade.ui()) + .doOnSubscribe(__ -> mProcessing.setValue(true)) + .doFinally(() -> mProcessing.setValue(false)) + .subscribe( + linkedRoles -> { + for (String role : linkedRoles) { + mLinkedRoles.setValue(role); + } + }, + throwable -> mError.setValue(new ViewModelError(LinkedRolesViewModel.Error.RETRIEVE, null)) + )); + } + + public void addLinkedRole(String deviceId, Role deviceRole, String roleId, String roleAuthority) { + Completable useCase; + if (deviceRole.equals(Role.CLIENT)) { + useCase = mLinkRolesForClientUseCase.execute(deviceId, roleId, roleAuthority); + } else { + useCase = mLinkRolesForServerUseCase.execute(deviceId, roleId, roleAuthority); + } + + mDisposables.add(useCase + .subscribeOn(mSchedulersFacade.io()) + .observeOn(mSchedulersFacade.ui()) + .doOnSubscribe(__ -> mProcessing.setValue(true)) + .doFinally(() -> mProcessing.setValue(false)) + .subscribe( + () -> retrieveLinkedRoles(deviceId, deviceRole), + throwable -> mError.setValue(new ViewModelError(Error.CREATE, null)) + )); + } + + public void deleteLinkedRole(String deviceId, Role deviceRole, String roleId) { + Completable useCase; + if (deviceRole.equals(Role.CLIENT)) { + useCase = mUnlinkRoleForClientUseCase.execute(deviceId, roleId); + } else { + useCase = mUnlinkRoleForServerUseCase.execute(deviceId, roleId); + } + + mDisposables.add(useCase + .subscribeOn(mSchedulersFacade.io()) + .observeOn(mSchedulersFacade.ui()) + .doOnSubscribe(__ -> mProcessing.setValue(true)) + .doFinally(() -> mProcessing.setValue(false)) + .subscribe( + () -> mDeletedRoleId.setValue(roleId), + throwable -> mError.setValue(new ViewModelError(Error.DELETE, null)) + )); + } + + public enum Error implements ViewModelErrorType { + CREATE, + RETRIEVE, + DELETE + } +} diff --git a/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/view/LoginActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/view/LoginActivity.java index 75d4353a087452875321885120d99702345aba9a..435ccee4596d4cd6ddb918de0a275d612256276e 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/view/LoginActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/view/LoginActivity.java @@ -19,14 +19,14 @@ * ******************************************************************/ package org.openconnectivity.otgc.login.presentation.view; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; -import android.support.design.widget.TextInputEditText; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.textfield.TextInputEditText; +import androidx.appcompat.app.AppCompatActivity; import android.text.Editable; import android.view.View; import android.view.Window; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/viewmodel/LoginViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/viewmodel/LoginViewModel.java index 3fb997133d9fdcd90503d4359c73ecddbe79bcba..115d2b20a7a6415ed684b2bcfd607ac62deafbb9 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/viewmodel/LoginViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/login/presentation/viewmodel/LoginViewModel.java @@ -19,9 +19,9 @@ * ******************************************************************/ package org.openconnectivity.otgc.login.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelError; import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelErrorType; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/logviewer/presentation/view/LogViewerActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/logviewer/presentation/view/LogViewerActivity.java index 9188e94029c62677f59e5504ee0bb959ab422251..3f0b5c184451ac01e1a8d3c023a9c7cfb0a2ae68 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/logviewer/presentation/view/LogViewerActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/logviewer/presentation/view/LogViewerActivity.java @@ -22,9 +22,15 @@ package org.openconnectivity.otgc.logviewer.presentation.view; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; +import butterknife.BindView; +import butterknife.ButterKnife; + import android.os.Bundle; import android.webkit.WebView; +import android.widget.Switch; + +import org.openconnectivity.otgc.R; import java.text.SimpleDateFormat; import java.util.Date; @@ -32,13 +38,31 @@ import java.util.Locale; public class LogViewerActivity extends AppCompatActivity { + @BindView(R.id.logviewer_iotivity_switch) Switch logSwitch; + @BindView(R.id.logviewer_webview) WebView webView; + + private String iotivityLog = ""; + private String otgcLog = ""; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - WebView webView = new WebView(this); - setContentView(webView); + setContentView(R.layout.activity_logviewer); + ButterKnife.bind(this); String fileNameTimeStamp = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(new Date()); - webView.loadUrl("file:///" + getExternalFilesDir(null).toString() + "/" + fileNameTimeStamp + ".html"); + otgcLog = "file:///" + getExternalFilesDir(null).toString() + "/" + fileNameTimeStamp + ".html"; + iotivityLog = "file:///" + getExternalFilesDir(null).toString() + "/log/logcat" + fileNameTimeStamp + ".html"; + + logSwitch.setOnClickListener(v -> loadWebView() ); + webView.loadUrl(iotivityLog); + } + + private void loadWebView() { + if (logSwitch.isChecked()) { + webView.loadUrl(iotivityLog); + } else { + webView.loadUrl(otgcLog); + } } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/AppCompatPreferenceActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/AppCompatPreferenceActivity.java index 1b67b0e47d124be3dd7c3113e7bb3f8722857c99..fdd1c725c9e31a5fb32264455a2ac004bdf615a2 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/AppCompatPreferenceActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/AppCompatPreferenceActivity.java @@ -25,12 +25,12 @@ package org.openconnectivity.otgc.settings.presentation.view; import android.content.res.Configuration; import android.os.Bundle; import android.preference.PreferenceActivity; -import android.support.annotation.LayoutRes; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatDelegate; -import android.support.v7.widget.Toolbar; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.widget.Toolbar; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/SettingsActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/SettingsActivity.java index f5309aef24ae1763de9503708eb8b8c55f14aef0..e433797fc6cb814c1652fd8b15196d644fc5e047 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/SettingsActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/settings/presentation/view/SettingsActivity.java @@ -33,7 +33,7 @@ import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; -import android.support.v7.widget.Toolbar; +import androidx.appcompat.widget.Toolbar; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MenuItem; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/view/SplashActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/view/SplashActivity.java index 72f25beef84168f069561ea564883fe8c90c6024..f13e41bbb2928fa71623b0b6de78eb7f5b5126e9 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/view/SplashActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/view/SplashActivity.java @@ -24,18 +24,18 @@ package org.openconnectivity.otgc.splash.presentation.view; import android.Manifest; import android.app.Dialog; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; import android.content.Intent; import android.net.Uri; import android.provider.Settings; -import android.support.annotation.NonNull; -import android.support.v4.app.ActivityCompat; -import android.support.v4.app.ActivityOptionsCompat; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; +import androidx.core.app.ActivityOptionsCompat; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; -import android.support.v7.view.ContextThemeWrapper; +import androidx.appcompat.view.ContextThemeWrapper; import android.view.View; import android.widget.TextView; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/viewmodel/SplashViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/viewmodel/SplashViewModel.java index e848af33ff5bdf33df34440ceacd8e78895b84eb..05f369eae5b9574c82301173cd1a18f0ee673e2e 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/viewmodel/SplashViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/splash/presentation/viewmodel/SplashViewModel.java @@ -22,10 +22,10 @@ package org.openconnectivity.otgc.splash.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; -import android.arch.persistence.room.EmptyResultSetException; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; +import androidx.room.EmptyResultSetException; import org.openconnectivity.otgc.common.presentation.viewmodel.ViewModelError; import org.openconnectivity.otgc.common.domain.rx.SchedulersFacade; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/domain/usecase/ConnectToWiFiUseCase.java b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/domain/usecase/ConnectToWiFiUseCase.java index 0c4ac0676b146beee0fc9034b849b546ecd60315..9d6ff011d55c31b6759e15e25b9de6ff4e825c5b 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/domain/usecase/ConnectToWiFiUseCase.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/domain/usecase/ConnectToWiFiUseCase.java @@ -56,13 +56,7 @@ public class ConnectToWiFiUseCase { return wlanRepository.isWifiEnabled() .andThen(wlanRepository.getWifiConfiguration(network.getName())) - .flatMap(config -> { - if (config == null) { - return configureWifiNetwork; - } else { - return Single.just(config); - } - }) + .onErrorResumeNext(configureWifiNetwork) .flatMapCompletable(wlanRepository::connectToWifi); } } diff --git a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanActivity.java b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanActivity.java index 70b0acb7cb060f2447e56353c0a10af7a693f4ed..efbbf73be6d2c9c6ce9003fae33857e284ff3bef 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanActivity.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanActivity.java @@ -22,20 +22,20 @@ package org.openconnectivity.otgc.wlanscan.presentation.view; import android.app.AlertDialog; -import android.arch.lifecycle.ViewModelProvider; -import android.arch.lifecycle.ViewModelProviders; +import androidx.lifecycle.ViewModelProvider; +import androidx.lifecycle.ViewModelProviders; //import android.net.wifi.ScanResult; import android.net.wifi.SupplicantState; import android.net.wifi.WifiManager; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.design.widget.TextInputEditText; -import android.support.v4.widget.SwipeRefreshLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; +import androidx.annotation.NonNull; +import com.google.android.material.textfield.TextInputEditText; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AppCompatActivity; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.appcompat.widget.Toolbar; import android.view.MenuItem; import android.view.View; import android.widget.ProgressBar; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanAdapter.java b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanAdapter.java index 3e2c6879f362c418458a4bfbcea3468284349411..f4c0932cb60a80386769ed825e00bc147f25536c 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanAdapter.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/view/WlanScanAdapter.java @@ -24,9 +24,9 @@ package org.openconnectivity.otgc.wlanscan.presentation.view; import android.content.Context; import android.graphics.drawable.Drawable; -import android.support.annotation.NonNull; -import android.support.v4.content.ContextCompat; -import android.support.v7.widget.RecyclerView; +import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; diff --git a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/viewmodel/WlanScanViewModel.java b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/viewmodel/WlanScanViewModel.java index 13b37b4604d72465b0a584bb92f0f1b5169ee379..9d202aebd6d20006b4a78fb4404475f1b68e0ba9 100644 --- a/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/viewmodel/WlanScanViewModel.java +++ b/otgc/src/main/java/org/openconnectivity/otgc/wlanscan/presentation/viewmodel/WlanScanViewModel.java @@ -22,9 +22,9 @@ package org.openconnectivity.otgc.wlanscan.presentation.viewmodel; -import android.arch.lifecycle.LiveData; -import android.arch.lifecycle.MutableLiveData; -import android.arch.lifecycle.ViewModel; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; import android.net.wifi.SupplicantState; import org.openconnectivity.otgc.common.domain.usecase.CheckConnectionUseCase; diff --git a/otgc/src/main/res/color/device_background.xml b/otgc/src/main/res/color/device_background.xml new file mode 100644 index 0000000000000000000000000000000000000000..a31029a6d9b5561f6ddabd08cd30d42dd097dad8 --- /dev/null +++ b/otgc/src/main/res/color/device_background.xml @@ -0,0 +1,27 @@ + + + + + + + \ No newline at end of file diff --git a/otgc/src/main/res/drawable-v23/ic_ocf_logo_white.xml b/otgc/src/main/res/drawable-v23/ic_ocf_logo_white.xml new file mode 100644 index 0000000000000000000000000000000000000000..607c8c1d689c42cb5622d4d2372ecd83cbc7620c --- /dev/null +++ b/otgc/src/main/res/drawable-v23/ic_ocf_logo_white.xml @@ -0,0 +1,44 @@ + + + + + + + + + + \ No newline at end of file diff --git a/otgc/src/main/res/drawable-v23/splash.xml b/otgc/src/main/res/drawable-v23/splash.xml new file mode 100644 index 0000000000000000000000000000000000000000..b6e6f6eb7a018599e0105e9aa6d1acaf4c5be39a --- /dev/null +++ b/otgc/src/main/res/drawable-v23/splash.xml @@ -0,0 +1,30 @@ + + + + + + + \ No newline at end of file diff --git a/otgc/src/main/res/drawable/splash.xml b/otgc/src/main/res/drawable/splash.xml index b6e6f6eb7a018599e0105e9aa6d1acaf4c5be39a..2b36bb0751ecfc11363e53c07b55cf1e00fe7bc5 100644 --- a/otgc/src/main/res/drawable/splash.xml +++ b/otgc/src/main/res/drawable/splash.xml @@ -23,8 +23,10 @@ - + android:drawable="@color/white1" /> + + + \ No newline at end of file diff --git a/otgc/src/main/res/layout/activity_access_control.xml b/otgc/src/main/res/layout/activity_access_control.xml index 8dbd48c54d97baba03aa0316d857888cd2fe92e1..43a166dd8a00e2a54a78752b9a7c22fb6b1b30a5 100644 --- a/otgc/src/main/res/layout/activity_access_control.xml +++ b/otgc/src/main/res/layout/activity_access_control.xml @@ -21,14 +21,14 @@ ~ ****************************************************************** --> - - @@ -41,14 +41,14 @@ - + - - \ No newline at end of file + \ No newline at end of file diff --git a/otgc/src/main/res/layout/activity_ace.xml b/otgc/src/main/res/layout/activity_ace.xml index 1922eef426c57e03e529a67fb1aa57df692c72f8..9f70afde5d3faa5265cf0959161dc730ae493f12 100644 --- a/otgc/src/main/res/layout/activity_ace.xml +++ b/otgc/src/main/res/layout/activity_ace.xml @@ -21,14 +21,14 @@ ~ ****************************************************************** --> - - @@ -41,7 +41,7 @@ - + - - - + - - - - + - - + - - \ No newline at end of file + \ No newline at end of file diff --git a/otgc/src/main/res/layout/activity_cred.xml b/otgc/src/main/res/layout/activity_cred.xml index fbc75ff4da0721facef10108b66720718ba09cf0..860a1611140a14c957b82b37f2deb0c24fd8c308 100644 --- a/otgc/src/main/res/layout/activity_cred.xml +++ b/otgc/src/main/res/layout/activity_cred.xml @@ -21,14 +21,14 @@ ~ ****************************************************************** --> - - @@ -41,7 +41,7 @@ - + - - - - + - - + - - \ No newline at end of file + \ No newline at end of file diff --git a/otgc/src/main/res/layout/activity_credentials.xml b/otgc/src/main/res/layout/activity_credentials.xml index 3432ee71981c21ab5d727875794f4be8873ff6c3..78ea7be0127d22a1daa744afa3aaa36fb44e27d4 100644 --- a/otgc/src/main/res/layout/activity_credentials.xml +++ b/otgc/src/main/res/layout/activity_credentials.xml @@ -21,14 +21,14 @@ ~ ****************************************************************** --> - - @@ -41,14 +41,14 @@ - + - - \ No newline at end of file + \ No newline at end of file diff --git a/otgc/src/main/res/layout/activity_devices.xml b/otgc/src/main/res/layout/activity_devices.xml index 6374709020405134dd5c6bb6312221f96c6846be..0e435781969c0fcdf9508e53bd902fc1d35f0958 100644 --- a/otgc/src/main/res/layout/activity_devices.xml +++ b/otgc/src/main/res/layout/activity_devices.xml @@ -21,14 +21,14 @@ ~ ****************************************************************** --> - - @@ -41,13 +41,13 @@ - + - - + diff --git a/otgc/src/main/res/layout/activity_generic_client.xml b/otgc/src/main/res/layout/activity_generic_client.xml index 38c482dd9a81800df6082f07c208cc80ec1c4f74..47ed2e3fb795ccff69f51ebd2d56202575a19f7a 100644 --- a/otgc/src/main/res/layout/activity_generic_client.xml +++ b/otgc/src/main/res/layout/activity_generic_client.xml @@ -21,7 +21,7 @@ ~ ****************************************************************** --> - - - \ No newline at end of file + \ No newline at end of file diff --git a/otgc/src/main/res/layout/activity_linked_roles.xml b/otgc/src/main/res/layout/activity_linked_roles.xml new file mode 100644 index 0000000000000000000000000000000000000000..d16804ad9fc41d696f67d87f099a16266b9e9ed1 --- /dev/null +++ b/otgc/src/main/res/layout/activity_linked_roles.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/otgc/src/main/res/layout/activity_login.xml b/otgc/src/main/res/layout/activity_login.xml index 33167ae9724469098fadc77d09f840b306209f86..e365db91722c65d9aa6f96c6ed6fa5ad33834670 100644 --- a/otgc/src/main/res/layout/activity_login.xml +++ b/otgc/src/main/res/layout/activity_login.xml @@ -37,10 +37,10 @@ android:adjustViewBounds="true" android:layout_marginBottom="@dimen/login_logo_margin_bottom" android:src="@drawable/ocf_logo_horizontal" /> - - - - + - - +