Skip to content

Commit

Permalink
feat: add HAL write operation
Browse files Browse the repository at this point in the history
  • Loading branch information
cinit committed Dec 18, 2021
1 parent d6647dd commit fb967a8
Show file tree
Hide file tree
Showing 13 changed files with 738 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package cc.ioctl.nfcdevicehost.activity.base;

import android.app.Dialog;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.core.view.WindowCompat;

import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.shape.MaterialShapeDrawable;
import com.google.android.material.shape.ShapeAppearanceModel;

import org.jetbrains.annotations.NotNull;

import cc.ioctl.nfcdevicehost.R;
import cc.ioctl.nfcdevicehost.util.ThreadManager;

public abstract class BaseBottomSheetDialogFragment extends BottomSheetDialogFragment {

private View mRootView = null;
private Dialog mDialog = null;
private BottomSheetBehavior mBehavior = null;
private final BottomSheetBehavior.BottomSheetCallback mBottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
if (newState == BottomSheetBehavior.STATE_EXPANDED) {
// In the EXPANDED STATE apply a new MaterialShapeDrawable with rounded corners
MaterialShapeDrawable newMaterialShapeDrawable = createMaterialShapeDrawable(bottomSheet);
bottomSheet.setBackground(newMaterialShapeDrawable);
}
}

@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// Do nothing
}
};

@NonNull
@UiThread
protected abstract View createRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState);

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mRootView = createRootView(inflater, container, savedInstanceState);
return mRootView;
}

@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
mDialog = new BottomSheetDialog(requireContext(), getTheme()) {
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
Window window = getWindow();
WindowCompat.setDecorFitsSystemWindows(window, false);
WindowManager.LayoutParams lp = window.getAttributes();
lp.gravity = Gravity.BOTTOM;
lp.windowAnimations = R.style.BottomSheetDialogAnimation;
window.setAttributes(lp);
}
};
return mDialog;
}

@Override
public void onStart() {
super.onStart();
if (mBehavior == null) {
mBehavior = BottomSheetBehavior.from((View) mRootView.getParent());
}
mBehavior.addBottomSheetCallback(mBottomSheetCallback);
// update bottom sheet background with round corners
View bottomSheet = mDialog.getWindow().findViewById(com.google.android.material.R.id.design_bottom_sheet);
ThreadManager.post(() -> {
// I don't know why, but this works, it won't work if you call it directly here
MaterialShapeDrawable newMaterialShapeDrawable = createMaterialShapeDrawable(bottomSheet);
bottomSheet.setBackground(newMaterialShapeDrawable);
});
}

@Override
public void onStop() {
super.onStop();
if (mBehavior != null) {
mBehavior.removeBottomSheetCallback(mBottomSheetCallback);
}
}

@Override
public void onDestroyView() {
mRootView = null;
super.onDestroyView();
}

@NotNull
private MaterialShapeDrawable createMaterialShapeDrawable(@NonNull View bottomSheet) {
// https://stackoverflow.com/questions/43852562/round-corner-for-bottomsheetdialogfragment
// Create a ShapeAppearanceModel with the same shapeAppearanceOverlay used in the style
ShapeAppearanceModel shapeAppearanceModel =
ShapeAppearanceModel.builder(getContext(), 0, R.style.CustomShapeAppearanceBottomSheetDialog)
.build();
//Create a new MaterialShapeDrawable (you can't use the original MaterialShapeDrawable in the BottoSheet)
MaterialShapeDrawable currentMaterialShapeDrawable = (MaterialShapeDrawable) bottomSheet.getBackground();
MaterialShapeDrawable newMaterialShapeDrawable = new MaterialShapeDrawable((shapeAppearanceModel));
//Copy the attributes in the new MaterialShapeDrawable
newMaterialShapeDrawable.initializeElevationOverlay(getContext());
newMaterialShapeDrawable.setFillColor(currentMaterialShapeDrawable.getFillColor());
newMaterialShapeDrawable.setTintList(currentMaterialShapeDrawable.getTintList());
newMaterialShapeDrawable.setElevation(currentMaterialShapeDrawable.getElevation());
newMaterialShapeDrawable.setStrokeWidth(currentMaterialShapeDrawable.getStrokeWidth());
newMaterialShapeDrawable.setStrokeColor(currentMaterialShapeDrawable.getStrokeColor());
return newMaterialShapeDrawable;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package cc.ioctl.nfcdevicehost.activity.ui.dump;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.appcompat.app.AlertDialog;

import com.google.android.material.snackbar.Snackbar;

import java.io.ByteArrayOutputStream;

import cc.ioctl.nfcdevicehost.R;
import cc.ioctl.nfcdevicehost.activity.base.BaseBottomSheetDialogFragment;
import cc.ioctl.nfcdevicehost.databinding.DialogBsdHalOperationBinding;
import cc.ioctl.nfcdevicehost.ipc.daemon.INciHostDaemon;
import cc.ioctl.nfcdevicehost.ipc.daemon.IpcNativeHandler;
import cc.ioctl.nfcdevicehost.util.Errno;
import cc.ioctl.nfcdevicehost.util.ThreadManager;

public class HalOperationDialogFragment extends BaseBottomSheetDialogFragment implements AdapterView.OnItemSelectedListener {

private DialogBsdHalOperationBinding mBinding;

@NonNull
@Override
protected View createRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
mBinding = DialogBsdHalOperationBinding.inflate(inflater, container, false);
mBinding.halOperationButtonSubmit.setOnClickListener(v -> submitOperation());
mBinding.halOperationButtonClose.setOnClickListener(v -> dismiss());
mBinding.halOperationSpinnerSyscallType.setAdapter(new ArrayAdapter<>(requireContext(),
R.layout.item_spinner_text, R.id.item_spinner_item_textView, new String[]{"WRITE"}));
mBinding.halOperationSpinnerSyscallType.setOnItemSelectedListener(this);
return mBinding.getRoot();
}

@UiThread
private void submitOperation() {
String input = mBinding.halOperationEditTextWritePayload.getText().toString();
String[] inputSplit = input.split("[,\n, |-]");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
for (String s : inputSplit) {
if (s.isEmpty()) {
continue;
}
int value = Integer.parseInt(s, 16);
baos.write(value);
}
} catch (NumberFormatException e) {
new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(requireContext().getString(R.string.ui_dialog_error_message_invalid_input_syntax_v0s, e.getMessage()))
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show();
return;
}
byte[] bytes = baos.toByteArray();
if (bytes.length > 0) {
INciHostDaemon daemon = IpcNativeHandler.peekConnection();
if (daemon != null && daemon.isHwServiceConnected()) {
ThreadManager.async(() -> {
try {
int result = daemon.deviceDriverWriteRaw(bytes);
ThreadManager.runOnUiThread(() -> {
if (result < 0) {
String errMsg = Errno.getErrnoString(result);
if (errMsg == null) {
errMsg = "Unknown error: " + result;
}
String finalErrMsg = errMsg;
ThreadManager.runOnUiThread(() -> new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(finalErrMsg)
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show());
} else {
dismiss();
Snackbar.make(mBinding.getRoot(),
requireContext().getString(R.string.ui_toast_operation_success_v0s, result),
Snackbar.LENGTH_SHORT).show();
}
});
} catch (Exception e) {
ThreadManager.runOnUiThread(() -> new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(e.getMessage())
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show());
}
});
} else {
new AlertDialog.Builder(requireContext())
.setTitle(R.string.ui_dialog_error_title)
.setMessage(R.string.ui_toast_hal_service_not_attached)
.setCancelable(true)
.setPositiveButton(android.R.string.ok, null)
.show();
dismiss();
}
}
}

@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

}

@Override
public void onNothingSelected(AdapterView<?> parent) {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ public void onResume() {
Activity activity = getActivity();
if (activity instanceof MainUiFragmentActivity) {
FloatingActionButton fab = ((MainUiFragmentActivity) activity).showFloatingActionButton();
fab.setOnClickListener(v -> Snackbar.make(v, R.string.ui_toast_not_implemented, Snackbar.LENGTH_SHORT).show());
fab.setOnClickListener(v -> showDeviceDriverRawIoOperationDialog());
}
INciHostDaemon daemon = IpcNativeHandler.peekConnection();
if (daemon == null) {
Expand All @@ -115,6 +115,12 @@ public void onResume() {
}
}

@UiThread
private void showDeviceDriverRawIoOperationDialog() {
HalOperationDialogFragment dialog = new HalOperationDialogFragment();
dialog.show(requireActivity().getSupportFragmentManager(), getTag());
}

@UiThread
public void jumpToHomeFragment() {
MainUiFragmentActivity activity = (MainUiFragmentActivity) requireActivity();
Expand Down
Loading

0 comments on commit fb967a8

Please sign in to comment.