Skip to content

Commit

Permalink
add license notice dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
cinit committed Dec 22, 2021
1 parent 82c3deb commit 49ee293
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,21 @@
import cc.ioctl.nfcdevicehost.util.ThreadManager;

public abstract class BaseBottomSheetDialogFragment extends BottomSheetDialogFragment {

// TODO: 2021-12-22 don't use rounded corners if the bottom sheet is expanded to the status bar or the top of window
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);
// don't use rounded corners if the bottom sheet is expanded to the status bar or the top of the screen
boolean isExpandedToWindowTop = mBehavior.getPeekHeight() == 0;
if (!isExpandedToWindowTop) {
// In the EXPANDED STATE apply a new MaterialShapeDrawable with rounded corners
MaterialShapeDrawable newMaterialShapeDrawable = createMaterialShapeDrawable(bottomSheet);
bottomSheet.setBackground(newMaterialShapeDrawable);
}
}
}

Expand Down Expand Up @@ -71,6 +75,15 @@ public void onAttachedToWindow() {
lp.gravity = Gravity.BOTTOM;
lp.windowAnimations = R.style.BottomSheetDialogAnimation;
window.setAttributes(lp);
// allow the bottom sheet to extend under the system status bar
View containerView = findViewById(com.google.android.material.R.id.container);
if (containerView != null) {
containerView.setFitsSystemWindows(false);
}
View coordinatorView = findViewById(com.google.android.material.R.id.coordinator);
if (coordinatorView != null) {
coordinatorView.setFitsSystemWindows(false);
}
}
};
return mDialog;
Expand All @@ -84,12 +97,17 @@ public void onStart() {
}
mBehavior.addBottomSheetCallback(mBottomSheetCallback);
// update bottom sheet background with round corners
// don't use rounded corners if the bottom sheet is expanded to the status bar or the top of the screen
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);
});
boolean isExpandedToWindowTop = (mBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED)
&& (mBehavior.getPeekHeight() == 0);
if (!isExpandedToWindowTop) {
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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package cc.ioctl.nfcdevicehost.activity.ui.misc

import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import cc.ioctl.nfcdevicehost.activity.base.BaseBottomSheetDialogFragment
import cc.ioctl.nfcdevicehost.databinding.DialogLicenseNoticeBinding
import cc.ioctl.nfcdevicehost.databinding.ItemLicenseNoticeBinding
import de.psdev.licensesdialog.LicensesDialog
import de.psdev.licensesdialog.licenses.ApacheSoftwareLicense20
import de.psdev.licensesdialog.licenses.BSD3ClauseLicense
import de.psdev.licensesdialog.model.Notice
import de.psdev.licensesdialog.model.Notices
import io.noties.markwon.Markwon

class LicenseNoticeDialogFragment : BaseBottomSheetDialogFragment() {

private var binding: DialogLicenseNoticeBinding? = null

override fun createRootView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = DialogLicenseNoticeBinding.inflate(inflater, container, false)
binding!!.dialogButtonClose.setOnClickListener { dismiss() }
val recycleView = binding!!.dialogRecyclerViewNotices
recycleView.adapter = LicenseNoticesAdapter(requireContext())
return binding!!.root
}

override fun onDestroyView() {
super.onDestroyView()
binding = null
}

class LicenseNoticeViewHolder(val binding: ItemLicenseNoticeBinding) :
RecyclerView.ViewHolder(binding.root) {
}

class LicenseNoticesAdapter(val context: Context) :
RecyclerView.Adapter<LicenseNoticeViewHolder>() {
private val markwon: Markwon = Markwon.create(context)
private val notices: Notices = Notices().also {
it.addNotice(
Notice(
"Markwon",
"https://github.com/noties/Markwon",
"Copyright 2017 Dimitry Ivanov ([email protected])",
ApacheSoftwareLicense20()
)
)
it.addNotice(
Notice(
"MMKV", "https://github.com/Tencent/MMKV",
"Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved.",
BSD3ClauseLicense()
)
)
it.addNotice(
Notice(
"nfcandroid_nfc_hidlimpl",
"https://github.com/NXPNFCProject/nfcandroid_nfc_hidlimpl",
"Copyright 2020-2021 NXP",
ApacheSoftwareLicense20()
)
)
it.addNotice(
Notice(
"AndroidHiddenApiBypass",
"https://github.com/LSPosed/AndroidHiddenApiBypass",
"Copyright (C) 2021 LSPosed",
ApacheSoftwareLicense20()
)
)
it.addNotice(
Notice(
"libsu",
"https://github.com/topjohnwu/libsu",
"Copyright 2021 John \"topjohnwu\" Wu",
ApacheSoftwareLicense20()
)
)
it.addNotice(
Notice(
"Xposed",
"https://github.com/rovo89/XposedBridge",
"Copyright 2013 rovo89, Tungstwenty",
ApacheSoftwareLicense20()
)
)
it.addNotice(LicensesDialog.LICENSES_DIALOG_NOTICE)
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
LicenseNoticeViewHolder(
ItemLicenseNoticeBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)

@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: LicenseNoticeViewHolder, position: Int) {
val notice = notices.notices[position]
val title: TextView = holder.binding.sLicenseItemTitle
val licenseView: TextView = holder.binding.sLicenseItemLicensePrev
markwon.setMarkdown(title, "- " + notice.name + " \n<" + notice.url + ">")
licenseView.text = notice.copyright + "\n\n" + notice.license.getSummaryText(context)
}

override fun getItemCount() = notices.notices.size
}
}
Original file line number Diff line number Diff line change
@@ -1,46 +1,87 @@
package cc.ioctl.nfcdevicehost.activity.ui.settings;
package cc.ioctl.nfcdevicehost.activity.ui.settings

import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.app.Activity
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.preference.Preference
import cc.ioctl.nfcdevicehost.R
import cc.ioctl.nfcdevicehost.activity.MainUiFragmentActivity
import cc.ioctl.nfcdevicehost.activity.base.BasePreferenceFragment
import cc.ioctl.nfcdevicehost.activity.ui.misc.LicenseNoticeDialogFragment
import cc.ioctl.nfcdevicehost.ipc.daemon.IpcNativeHandler
import cc.ioctl.nfcdevicehost.util.ThreadManager.async
import cc.ioctl.nfcdevicehost.util.ThreadManager.runOnUiThread
import cc.ioctl.nfcdevicehost.util.config.GenericConfig
import com.google.android.material.snackbar.Snackbar

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;

import cc.ioctl.nfcdevicehost.R;
import cc.ioctl.nfcdevicehost.activity.MainUiFragmentActivity;
import cc.ioctl.nfcdevicehost.activity.base.BasePreferenceFragment;

public class SettingsFragment extends BasePreferenceFragment {

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
Activity activity = getActivity();
if (activity instanceof AppCompatActivity) {
ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
class SettingsFragment : BasePreferenceFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val activity: Activity? = activity
if (activity is AppCompatActivity) {
val actionBar = activity.supportActionBar
actionBar?.setDisplayHomeAsUpEnabled(true)
}
return super.onCreateView(inflater, container, savedInstanceState);
return super.onCreateView(inflater, container, savedInstanceState)
}

@Override
public void onResume() {
super.onResume();
Activity activity = getActivity();
if (activity instanceof MainUiFragmentActivity) {
((MainUiFragmentActivity) activity).hideFloatingActionButton();
override fun onResume() {
super.onResume()
val activity: Activity? = activity
if (activity is MainUiFragmentActivity) {
activity.hideFloatingActionButton()
}
}

@Override
public void doOnCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.root_preferences, rootKey);
public override fun doOnCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
preferenceScreen.findPreference<Preference>("pref_open_source_licenses")!!
.setOnPreferenceClickListener {
val dialog = LicenseNoticeDialogFragment()
dialog.show(requireActivity().supportFragmentManager, tag)
true
}
GenericConfig.cfgDisableNfcDiscoverySound.observe(this) { value: Boolean ->
val view = requireActivity().window.decorView
val daemon = IpcNativeHandler.peekConnection()
if (daemon == null) {
Snackbar.make(view, R.string.ui_toast_daemon_is_not_running, Snackbar.LENGTH_SHORT)
.show()
} else {
val r = Runnable {
if (!daemon.isAndroidNfcServiceConnected) {
Snackbar.make(
view, R.string.ui_toast_android_nfc_service_not_connected,
Snackbar.LENGTH_SHORT
).show()
} else {
async {
val result = daemon.setNfcDiscoverySoundDisabled(value)
if (!result) {
runOnUiThread {
Snackbar.make(
view,
R.string.ui_toast_operation_failed, Snackbar.LENGTH_SHORT
).show()
}
}
}
}
}
if (!daemon.isAndroidNfcServiceConnected) {
async {
daemon.connectToAndroidNfcService()
runOnUiThread(r)
}
} else {
r.run()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class GenericConfig {
public static final NonNullConfigItem<String> cfgNfcDeviceType =
new LazyNonNullMmkvItemConfig<>("core", "cfg_nfc_device_type", "sn100x");
public static final NonNullConfigItem<Boolean> cfgDisableNfcDiscoverySound =
new NonNullConstantValueConfigItem<>(false, false);
new LazyNonNullMmkvItemConfig<>("core", "cfg_disable_nfc_discovery_sound", false);
public static final NonNullConfigItem<Boolean> cfgEnableNfcEmulationWhenScreenOff =
new NonNullConstantValueConfigItem<>(false, false);

Expand Down
58 changes: 58 additions & 0 deletions app/src/main/res/layout/dialog_license_notice.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="8dp"
android:layout_marginRight="16dp"
android:gravity="center_vertical">

<TextView
style="@style/TextAppearance.AppCompat.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center_horizontal"
android:text="@string/notices_title" />

<TextView
android:id="@+id/dialog_button_close"
style="@style/TextAppearance.AppCompat.Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:background="@drawable/bg_ripple_round_rect"
android:clickable="true"
android:focusable="true"
android:gravity="center"
android:minWidth="64dp"
android:minHeight="48dp"
android:paddingLeft="16dp"
android:paddingTop="12dp"
android:paddingRight="16dp"
android:paddingBottom="12dp"
android:text="@string/notices_close"
android:textColor="?colorAccent"
android:textSize="16sp" />

</RelativeLayout>

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dialog_recycler_view_notices"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:fadeScrollbars="true"
android:scrollbarStyle="insideOverlay"
android:scrollbars="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

</LinearLayout>
Loading

0 comments on commit 49ee293

Please sign in to comment.