Unverified Commit cdfc7cc6 authored by Javier Guerra's avatar Javier Guerra Committed by GitHub

Merge pull request #10 from openconnectivity/develop

Merge develop into master
parents 1e92dc5c 6edcd001
......@@ -30,7 +30,7 @@ android {
minSdkVersion 21
targetSdkVersion 28
versionCode 13
versionName "2.0.7"
versionName "2.0.8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
compileOptions {
......
......@@ -144,7 +144,7 @@ public class IotivityRepository {
public int initialize() {
Timber.d("In OCMainInitHandler.initilize()");
int ret = OCMain.initPlatform("OCF");
ret |= OCMain.addDevice("/oic/d", "oic.d.phone", "OTGC", "ocf.2.4.0", "ocf.res.1.3.0");
ret |= OCMain.addDevice("/oic/d", "oic.wk.d", "OTGC", "ocf.2.4.0", "ocf.res.1.3.0");
return ret;
}
......@@ -468,7 +468,7 @@ public class IotivityRepository {
List<OcResource> resourceList = new ArrayList<>();
for (OcResource resource : ocRes.getResourceList()) {
for (String resourceType : resource.getResourceTypes()) {
if (!RESOURCE_TYPES_TO_FILTER.contains(resourceType)
if (OcfResourceType.isVerticalResourceType(resourceType)
&& !resourceType.startsWith("oic.d.")) {
resourceList.add(resource);
break;
......
......@@ -62,9 +62,10 @@ public class OffboardUseCase {
return doxsRepository.resetDevice(deviceToOffboard.getDeviceId())
.delay(preferencesRepository.getRequestsDelay(), TimeUnit.SECONDS, schedulersFacade.ui())
.andThen(getUpdatedOcSecureResource)
.onErrorResumeNext(error -> getUpdatedOcSecureResource
.retry(2)
.onErrorResumeNext(Single.error(error)));
.andThen(getUpdatedOcSecureResource
.onErrorResumeNext(error -> getUpdatedOcSecureResource
.retry(2)
.onErrorResumeNext(Single.error(error)))
);
}
}
......@@ -62,9 +62,10 @@ public class OnboardUseCase {
return doxsRepository.doOwnershipTransfer(deviceToOnboard.getDeviceId(), oxm)
.delay(preferencesRepository.getRequestsDelay(), TimeUnit.SECONDS, schedulersFacade.ui())
.andThen(getUpdatedOcSecureResource)
.onErrorResumeNext(error -> getUpdatedOcSecureResource
.retry(2)
.onErrorResumeNext(Single.error(error)));
.andThen(getUpdatedOcSecureResource
.onErrorResumeNext(error -> getUpdatedOcSecureResource
.retry(2)
.onErrorResumeNext(Single.error(error)))
);
}
}
package org.openconnectivity.otgc.domain.usecase;
import org.openconnectivity.otgc.data.repository.PreferencesRepository;
import org.openconnectivity.otgc.data.repository.ProvisioningRepository;
import org.openconnectivity.otgc.utils.constant.OtgcMode;
import javax.inject.Inject;
import io.reactivex.Completable;
public class ResetClientModeUseCase {
private final ProvisioningRepository provisioningRepository;
private final PreferencesRepository preferencesRepository;
@Inject
public ResetClientModeUseCase(ProvisioningRepository provisioningRepository,
PreferencesRepository preferencesRepository) {
this.provisioningRepository = provisioningRepository;
this.preferencesRepository = preferencesRepository;
}
public Completable execute() {
return provisioningRepository.resetSvrDb()
.andThen(Completable.fromAction(() -> preferencesRepository.setMode(OtgcMode.CLIENT)));
}
}
package org.openconnectivity.otgc.domain.usecase;
import org.openconnectivity.otgc.data.repository.DoxsRepository;
import org.openconnectivity.otgc.data.repository.IotivityRepository;
import org.openconnectivity.otgc.data.repository.PreferencesRepository;
import org.openconnectivity.otgc.data.repository.ProvisioningRepository;
import org.openconnectivity.otgc.utils.constant.OtgcMode;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import io.reactivex.Completable;
public class ResetObtModeUseCase {
private final IotivityRepository iotivityRepository;
private final DoxsRepository doxsRepository;
private final ProvisioningRepository provisioningRepository;
private final PreferencesRepository preferencesRepository;
@Inject
public ResetObtModeUseCase(IotivityRepository iotivityRepository,
DoxsRepository doxsRepository,
ProvisioningRepository provisioningRepository,
PreferencesRepository preferencesRepository) {
this.iotivityRepository = iotivityRepository;
this.doxsRepository = doxsRepository;
this.provisioningRepository = provisioningRepository;
this.preferencesRepository = preferencesRepository;
}
public Completable execute() {
return iotivityRepository.scanOwnedDevices()
.flatMapCompletable(device -> doxsRepository.resetDevice(device.getDeviceId()))
.delay(preferencesRepository.getRequestsDelay(), TimeUnit.SECONDS)
.andThen(provisioningRepository.resetSvrDb())
.andThen(provisioningRepository.doSelfOwnership())
.andThen(Completable.fromAction(() -> preferencesRepository.setMode(OtgcMode.OBT)));
}
}
......@@ -33,7 +33,7 @@ public class SetClientModeUseCase {
public Completable execute() {
return iotivityRepository.scanOwnedDevices()
.flatMapCompletable(device -> doxsRepository.resetDevice(device.getDeviceId()))
.delay(preferencesRepository.getRequestsDelay(), TimeUnit.MILLISECONDS)
.delay(preferencesRepository.getRequestsDelay(), TimeUnit.SECONDS)
.andThen(provisioningRepository.resetSvrDb())
.andThen(Completable.fromAction(() -> preferencesRepository.setMode(OtgcMode.CLIENT)));
}
......
......@@ -22,23 +22,27 @@
package org.openconnectivity.otgc.view.devicelist;
import android.app.AlertDialog;
import android.content.Context;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import org.openconnectivity.otgc.R;
import org.openconnectivity.otgc.domain.model.devicelist.Device;
import org.openconnectivity.otgc.domain.model.devicelist.DeviceType;
import org.openconnectivity.otgc.domain.model.devicelist.DeviceRole;
import org.openconnectivity.otgc.domain.usecase.link.RetrieveLinkedDevicesUseCase;
import org.openconnectivity.otgc.utils.rx.SchedulersFacade;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import androidx.appcompat.view.ActionMode;
import androidx.recyclerview.selection.SelectionTracker;
import io.reactivex.disposables.CompositeDisposable;
public class ActionModeController implements ActionMode.Callback {
private final Context mContext;
private final SelectionTracker mSelectionTracker;
......@@ -83,25 +87,39 @@ public class ActionModeController implements ActionMode.Callback {
final Device c = client;
final Device s = server;
List<String> linkClientDevices = retrieveLinkedDevicesUseCase.execute(client)
.onErrorReturnItem(new ArrayList<>())
.blockingGet();
if (serverId != null) {
if (linkClientDevices.contains(serverId)) {
unlinkMenuItem.setOnMenuItemClickListener(menuItem -> {
actionMode.finish();
return sMyMenuItemClickListener.onMenuItemClick(menuItem, c, s);
});
unlinkMenuItem.setVisible(true);
} else {
linkMenuItem.setOnMenuItemClickListener(menuItem -> {
actionMode.finish();
return sMyMenuItemClickListener.onMenuItemClick(menuItem, c, s);
});
linkMenuItem.setVisible(true);
}
}
// Create dialog
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setTitle(R.string.dialog_wait_title);
builder.setMessage(R.string.dialog_wait_message);
AlertDialog waitDialog = builder.create();
new CompositeDisposable().add(retrieveLinkedDevicesUseCase.execute(c)
.onErrorReturnItem(new ArrayList<>())
.subscribeOn(new SchedulersFacade().io())
.observeOn(new SchedulersFacade().ui())
.doOnSubscribe(__ -> waitDialog.show())
.doFinally(() -> waitDialog.dismiss())
.subscribe(
linkClientDevices -> {
if (serverId != null) {
if (linkClientDevices.contains(serverId)) {
unlinkMenuItem.setOnMenuItemClickListener(menuItem -> {
actionMode.finish();
return sMyMenuItemClickListener.onMenuItemClick(menuItem, c, s);
});
unlinkMenuItem.setVisible(true);
} else {
linkMenuItem.setOnMenuItemClickListener(menuItem -> {
actionMode.finish();
return sMyMenuItemClickListener.onMenuItemClick(menuItem, c, s);
});
linkMenuItem.setVisible(true);
}
}
},
throwable -> Toast.makeText(mContext, R.string.devices_link_error, Toast.LENGTH_SHORT)
));
}
} else {
linkMenuItem.setVisible(false);
......
......@@ -34,7 +34,6 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.Toast;
......@@ -46,7 +45,6 @@ import org.openconnectivity.otgc.utils.viewmodel.CommonError;
import org.openconnectivity.otgc.utils.viewmodel.Response;
import org.openconnectivity.otgc.utils.viewmodel.Status;
import org.openconnectivity.otgc.utils.viewmodel.ViewModelError;
import org.openconnectivity.otgc.view.link.LinkedRolesActivity;
import org.openconnectivity.otgc.view.trustanchor.TrustAnchorActivity;
import org.openconnectivity.otgc.viewmodel.DeviceListViewModel;
import org.openconnectivity.otgc.viewmodel.SharedViewModel;
......@@ -105,16 +103,6 @@ public class DeviceListActivity extends AppCompatActivity implements HasSupportF
} catch (Exception e) {
Timber.e(e);
}
});
alertDialog.setNegativeButton(DeviceListActivity.this.getString(R.string.devices_dialog_insert_randompin_no_option), (dialog, which) -> {
dialog.dismiss();
try {
synchronized (lock) {
lock.notifyAll();
}
} catch (Exception e) {
Timber.e(e);
}
}).show();
});
synchronized (lock) {
......@@ -190,16 +178,16 @@ public class DeviceListActivity extends AppCompatActivity implements HasSupportF
switch (item.getItemId()) {
case R.id.menu_item_reset:
if (!obtMenuItem.isVisible()) {
showConfirmSetMode(OtgcMode.OBT);
showConfirmSetMode(OtgcMode.OBT, true);
} else if (!clientMenuItem.isVisible()) {
showConfirmSetMode(OtgcMode.CLIENT);
showConfirmSetMode(OtgcMode.CLIENT, true);
}
break;
case R.id.menu_item_obt_mode:
showConfirmSetMode(OtgcMode.OBT);
showConfirmSetMode(OtgcMode.OBT, false);
break;
case R.id.menu_item_client_mode:
showConfirmSetMode(OtgcMode.CLIENT);
showConfirmSetMode(OtgcMode.CLIENT, false);
break;
case R.id.menu_item_trust_anchor:
onTrustAnchorManagement();
......@@ -262,8 +250,8 @@ public class DeviceListActivity extends AppCompatActivity implements HasSupportF
SharedViewModel sharedViewModel = ViewModelProviders.of(this, mViewModelFactory).get(SharedViewModel.class);
sharedViewModel.getLoading().observe(this, this::processing);
sharedViewModel.getDisconnected().observe(this, isDisconnected -> {
processing(false);
goToWlanConnectSSID();
processing(false);
goToWlanConnectSSID();
});
}
......@@ -328,8 +316,8 @@ public class DeviceListActivity extends AppCompatActivity implements HasSupportF
private void processLogoutResponse(Response<Void> response) {
if (response.status.equals(Status.SUCCESS)) {
startActivity(new Intent(DeviceListActivity.this, LoginActivity.class));
finish();
startActivity(new Intent(DeviceListActivity.this, LoginActivity.class));
finish();
}
}
......@@ -376,18 +364,27 @@ public class DeviceListActivity extends AppCompatActivity implements HasSupportF
}
}
private void showConfirmSetMode(String mode) {
private void showConfirmSetMode(String mode, boolean reset) {
AlertDialog.Builder alertDialog = new AlertDialog.Builder(new ContextThemeWrapper(DeviceListActivity.this, R.style.AppTheme));
alertDialog.setTitle(this.getString(R.string.devices_dialog_confirm_reset_device_title));
alertDialog.setMessage(R.string.devices_dialog_confirm_reset_device_message);
alertDialog.setPositiveButton(this.getString(R.string.devices_dialog_confirm_reset_device_yes_option), (dialog, which) -> {
dialog.dismiss();
if (mode.equals(OtgcMode.OBT)) {
mViewModel.setObtMode();
} else if (mode.equals(OtgcMode.CLIENT)) {
mViewModel.setClientMode();
if (reset) {
if (mode.equals(OtgcMode.OBT)) {
mViewModel.resetObtMode();
} else if (mode.equals(OtgcMode.CLIENT)) {
mViewModel.resetClientMode();
}
} else {
if (mode.equals(OtgcMode.OBT)) {
mViewModel.setObtMode();
} else if (mode.equals(OtgcMode.CLIENT)) {
mViewModel.setClientMode();
}
}
});
alertDialog.setNegativeButton(this.getString(R.string.devices_dialog_confirm_reset_device_no_option), (dialog, which) -> dialog.dismiss()).show();
}
......
......@@ -48,6 +48,7 @@ import android.widget.Spinner;
import android.widget.Toast;
import org.openconnectivity.otgc.R;
import org.openconnectivity.otgc.domain.model.devicelist.DeviceType;
import org.openconnectivity.otgc.domain.usecase.link.RetrieveLinkedDevicesUseCase;
import org.openconnectivity.otgc.utils.constant.OcfOxmType;
import org.openconnectivity.otgc.view.accesscontrol.AccessControlActivity;
......@@ -127,6 +128,7 @@ public class DoxsFragment extends Fragment implements DoxsViewModel.SelectOxMLis
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mRecyclerView.setAdapter(getAdapter());
mRecyclerView.setEmptyView(null);
mRecyclerView.setItemAnimator(null);
if (getContext() != null) {
mSwipeToRefreshView.setColorSchemeColors(ContextCompat.getColor(getContext(), R.color.colorPrimary));
......@@ -266,6 +268,9 @@ public class DoxsFragment extends Fragment implements DoxsViewModel.SelectOxMLis
mViewModel.getDeviceFound().observe(this, this::processDeviceFound);
mViewModel.getOtmResponse().observe(this, this::processOtmResponse);
mViewModel.getDeviceInfoResponse().observe(this, this::processDeviceInfoResponse);
mViewModel.getDeviceRoleResponse().observe(this, this::processDeviceRoleResponse);
mViewModel.provisionAceOtmResponse().observe(this, this::processProvisionAceOtmResponse);
mViewModel.getOffboardResponse().observe(this, this::processOffboardResponse);
mViewModel.getUpdatedDevice().observe(this, this::processUpdateDevice);
......@@ -385,43 +390,81 @@ public class DoxsFragment extends Fragment implements DoxsViewModel.SelectOxMLis
private void processOtmResponse(Response<Device> response) {
switch (response.status) {
case LOADING:
renderOtmLoadingState();
adPersonal = UiUtils.createProgressDialog(getActivity(),
getString(R.string.devices_dialog_onboarding_otm_message));
break;
case SUCCESS:
renderOtmDataState(response.data);
break;
case ERROR:
renderOtmErrorState(response.message);
if (adPersonal != null && adPersonal.isShowing()) {
adPersonal.dismiss();
}
Toast.makeText(getActivity(), R.string.devices_error_transferring_ownership, Toast.LENGTH_SHORT).show();
break;
}
}
private void renderOtmLoadingState() {
adPersonal = UiUtils.createProgressDialog(getActivity(),
getString(R.string.devices_dialog_onboarding_otm_message));
private void processDeviceInfoResponse(Response<Device> response) {
switch (response.status) {
case LOADING:
break;
case SUCCESS:
break;
case ERROR:
if (adPersonal != null && adPersonal.isShowing()) {
adPersonal.dismiss();
}
Toast.makeText(getActivity(), R.string.devices_error_device_info, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
private void renderOtmDataState(Device data) {
if (adPersonal != null && adPersonal.isShowing()) {
adPersonal.dismiss();
}
private void processDeviceRoleResponse(Response<Device> response) {
switch (response.status) {
case LOADING:
break;
case SUCCESS:
if (adPersonal != null && adPersonal.isShowing()) {
adPersonal.dismiss();
}
if (data != null) {
positionBeingUpdated = mAdapter.updateItem(positionBeingUpdated, data);
showSetDeviceNameDialog(
positionBeingUpdated,
mAdapter.mDataset.get(positionBeingUpdated).getDeviceId(),
mAdapter.mDataset.get(positionBeingUpdated).getDeviceInfo().getName()
);
positionBeingUpdated = 0;
if (response.data != null) {
positionBeingUpdated = mAdapter.updateItem(positionBeingUpdated, response.data);
if (response.data.getDeviceType() == DeviceType.OWNED_BY_SELF) {
showSetDeviceNameDialog(
positionBeingUpdated,
mAdapter.mDataset.get(positionBeingUpdated).getDeviceId(),
mAdapter.mDataset.get(positionBeingUpdated).getDeviceInfo().getName()
);
}
positionBeingUpdated = 0;
}
break;
case ERROR:
if (adPersonal != null && adPersonal.isShowing()) {
adPersonal.dismiss();
}
Toast.makeText(getActivity(), R.string.devices_error_device_role, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
private void renderOtmErrorState(String message) {
if (adPersonal != null && adPersonal.isShowing()) {
adPersonal.dismiss();
private void processProvisionAceOtmResponse(Response<Device> response) {
switch (response.status) {
case LOADING:
break;
case SUCCESS:
break;
case ERROR:
Toast.makeText(getActivity(), R.string.devices_error_provision_ace_otm, Toast.LENGTH_SHORT).show();
break;
default:
break;
}
Toast.makeText(getActivity(), R.string.devices_error_transferring_ownership, Toast.LENGTH_SHORT).show();
}
private void processOffboardResponse(Response<Device> response) {
......@@ -431,13 +474,6 @@ public class DoxsFragment extends Fragment implements DoxsViewModel.SelectOxMLis
getString(R.string.devices_dialog_offboarding_reset_message));
break;
case SUCCESS:
if (adPersonal != null && adPersonal.isShowing()) {
adPersonal.dismiss();
}
if (response.data != null) {
mAdapter.updateItem(positionBeingUpdated, response.data);
positionBeingUpdated = 0;
}
break;
default:
if (adPersonal != null && adPersonal.isShowing()) {
......
......@@ -213,84 +213,86 @@ public class DoxsListAdapter extends RecyclerView.Adapter<DoxsListAdapter.DoxsLi
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(@NonNull DoxsListViewHolder holder, int position) {
// - get element from your dataset at this position
Device device = mDataset.get(position);
// - replace the contents of the view with that element
if (device.getDeviceInfo() != null) {
holder.mDeviceName.setText(
device.getDeviceInfo().getName().isEmpty() ?
mContext.getString(R.string.devices_cardview_unnamed_device) :
device.getDeviceInfo().getName()
);
if (!device.getDeviceInfo().getFormattedDeviceTypes().isEmpty()) {
holder.mDeviceType.setText(
TextUtils.join(",", device.getDeviceInfo().getFormattedDeviceTypes())
if (position != RecyclerView.NO_POSITION) {
// - get element from your dataset at this position
Device device = mDataset.get(position);
// - replace the contents of the view with that element
if (device.getDeviceInfo() != null) {
holder.mDeviceName.setText(
device.getDeviceInfo().getName().isEmpty() ?
mContext.getString(R.string.devices_cardview_unnamed_device) :
device.getDeviceInfo().getName()
);
if (!device.getDeviceInfo().getFormattedDeviceTypes().isEmpty()) {
holder.mDeviceType.setText(
TextUtils.join(",", device.getDeviceInfo().getFormattedDeviceTypes())
);
} else {
holder.mDeviceType.setText(mContext.getString(R.string.devices_cardview_no_device_types));
}
} else {
holder.mDeviceName.setText(mContext.getString(R.string.devices_cardview_unnamed_device));
holder.mDeviceType.setText(mContext.getString(R.string.devices_cardview_no_device_types));
}
} else {
holder.mDeviceName.setText(mContext.getString(R.string.devices_cardview_unnamed_device));
holder.mDeviceType.setText(mContext.getString(R.string.devices_cardview_no_device_types));
}
if (device.getDeviceRole().equals(DeviceRole.CLIENT)) {
holder.mDeviceRole.setText(mContext.getString(R.string.devices_cardview_role_client));
} else if (device.getDeviceRole().equals(DeviceRole.SERVER)) {
holder.mDeviceRole.setText(mContext.getString(R.string.devices_cardview_role_server));
} else {
holder.mDeviceRole.setText(mContext.getString(R.string.devices_cardview_role_unknown));
}
if (device.getDeviceRole().equals(DeviceRole.CLIENT)) {
holder.mDeviceRole.setText(mContext.getString(R.string.devices_cardview_role_client));
} else if (device.getDeviceRole().equals(DeviceRole.SERVER)) {
holder.mDeviceRole.setText(mContext.getString(R.string.devices_cardview_role_server));
} else {
holder.mDeviceRole.setText(mContext.getString(R.string.devices_cardview_role_unknown));
}
holder.mDeviceUuid.setText(device.getDeviceId());
holder.mDeviceUuid.setText(device.getDeviceId());
holder.mPopupButton.setOnClickListener(v -> {
PopupMenu popupMenu = new PopupMenu(mContext, holder.mPopupButton);
popupMenu.inflate(R.menu.menu_owned_devices);
popupMenu.setOnMenuItemClickListener(holder);
holder.mPopupButton.setOnClickListener(v -> {
PopupMenu popupMenu = new PopupMenu(mContext, holder.mPopupButton);
popupMenu.inflate(R.menu.menu_owned_devices);
popupMenu.setOnMenuItemClickListener(holder);
if (device.getDeviceType().equals(DeviceType.OWNED_BY_OTHER)) {
popupMenu.getMenu().findItem(R.id.menu_item_set_device_name).setVisible(false);
}
if (device.getDeviceType().equals(DeviceType.OWNED_BY_OTHER)) {
popupMenu.getMenu().findItem(R.id.menu_item_set_device_name).setVisible(false);
}
popupMenu.show();
});
popupMenu.show();
});
int color = ContextCompat.getColor(mContext, R.color.OCF_BLACK);
switch (device.getDeviceType()) {
case UNOWNED:
color = ContextCompat.getColor(mContext, R.color.ocf_light_blue);
holder.mAddDeviceButton.setVisibility(View.VISIBLE);
holder.mClientButton.setVisibility(View.GONE);
holder.mPopupButton.setVisibility(View.GONE);
break;
case OWNED_BY_SELF:
color = ContextCompat.getColor(mContext, R.color.ocf_green);
holder.mAddDeviceButton.setVisibility(View.GONE);
holder.mClientButton.setVisibility(View.VISIBLE);
holder.mPopupButton.setVisibility(View.VISIBLE);
break;
case OWNED_BY_OTHER:
color = ContextCompat.getColor(mContext, R.color.OCF_ORANGE);
holder.mAddDeviceButton.setVisibility(View.GONE);
holder.mClientButton.setVisibility(View.VISIBLE);
holder.mPopupButton.setVisibility(View.VISIBLE);
break;