Java tutorial
/* AccessLogActivity.java Copyright (c) 2014 NTT DOCOMO,INC. Released under the MIT license http://opensource.org/licenses/mit-license.php */ package org.deviceconnect.android.manager.accesslog; import android.annotation.SuppressLint; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; import android.support.design.widget.Snackbar; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.content.ContextCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AlertDialog; import android.support.v7.widget.DividerItemDecoration; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; import android.widget.TextView; import org.deviceconnect.android.manager.R; import org.deviceconnect.server.nanohttpd.accesslog.AccessLog; import org.deviceconnect.server.nanohttpd.accesslog.AccessLogProvider; import org.deviceconnect.android.manager.setting.BaseSettingActivity; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * ???? Activity. * * @author NTT DOCOMO, INC. */ public class AccessLogActivity extends BaseSettingActivity { /** * ?. */ private AccessLogProvider mAccessLogProvider; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); mAccessLogProvider = new AccessLogProvider(getApplicationContext()); setTitle(R.string.activity_settings_accesslog); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true); } if (savedInstanceState == null) { addFragment(DateListFragment.create(), false); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { callFragment(); } return super.onKeyDown(keyCode, event); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: callFragment(); FragmentManager manager = getSupportFragmentManager(); if (manager.getBackStackEntryCount() > 0) { manager.popBackStack(); } else { finish(); } return true; } return super.onOptionsItemSelected(item); } /** * Fragment ? {@link BaseFragment#onReturn()} ????. */ private void callFragment() { FragmentManager manager = getSupportFragmentManager(); List<Fragment> fragments = manager.getFragments(); for (Fragment fragment : fragments) { if (fragment instanceof BaseFragment) { ((BaseFragment) fragment).onReturn(); } } } /** * ???. * * @param fragment ? * @param isBackStack ?????true????false */ private void addFragment(Fragment fragment, boolean isBackStack) { FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(android.R.id.content, fragment, "container"); if (isBackStack) { transaction.addToBackStack(null); } transaction.commit(); } /** * ???. * * @param fragment ? */ private void addFragment(Fragment fragment) { addFragment(fragment, true); } /** * AccessLogProvider ?????. * * @return AccessLogProvider ? */ private AccessLogProvider getAccessLogProvider() { return mAccessLogProvider; } /** * ?. */ public static abstract class BaseFragment extends Fragment { /** * ???. */ private Handler mHandler = new Handler(Looper.getMainLooper()); /** * ?. */ private AccessLogProvider mAccessLogProvider; @Override public void onResume() { super.onResume(); AccessLogActivity activity = (AccessLogActivity) getActivity(); if (activity != null) { mAccessLogProvider = activity.getAccessLogProvider(); } } /** * ?????????. */ void onReturn() { } /** * ?? Fragment ???. * <p> * ?? Fragment ?????? Activity ??? * </p> */ void popFragment() { FragmentManager manager = getFragmentManager(); if (manager.getBackStackEntryCount() > 0) { manager.popBackStack(); } else { getActivity().finish(); } } /** * AccessLogProvider ?????. * <p> * Activity????????? null ???? * </p> * @return AccessLogProvider ? */ AccessLogProvider getAccessLogProvider() { return mAccessLogProvider; } /** * ?? Runnable ????. * * @param runnable ??Runnable */ void runOnUiThread(Runnable runnable) { mHandler.post(runnable); } /** * ???. * * @param fragment t */ void gotoFragment(Fragment fragment) { AccessLogActivity activity = (AccessLogActivity) getActivity(); if (activity != null) { activity.addFragment(fragment); } } } /** * RecyclerView?? RecyclerView.Adapter ???. * * @param <A> ? * @param <T> RecyclerView.ViewHolder?? */ private static abstract class BaseAdapter<A, T extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<T> { /** * ?. */ List<A> mDataList = new ArrayList<>(); /** * . */ LayoutInflater mInflater; /** * ??????. */ OnItemClickListener mOnItemClickListener; /** * ???. */ OnItemRemoveListener<A> mOnItemRemoveListener; /** * Undo??Snackbar. */ Snackbar mSnackbar; /** * . * @param inflater */ BaseAdapter(LayoutInflater inflater) { mInflater = inflater; } /** * Undo?? Snackbar ?????. */ void dismissSnackbar() { if (mSnackbar != null) { mSnackbar.dismiss(); } } /** * ???. * * @param dataList ?? */ void updateDataList(List<A> dataList) { if (dataList == null || mDataList.equals(dataList)) { return; } mDataList = dataList; notifyDataSetChanged(); } /** * ????????. * * @param position ? * @return */ A getItem(int position) { return mDataList.get(position); } @Override public int getItemCount() { return mDataList.size(); } /** * ???????????. * * @param viewHolder view * @param recyclerView View */ void onItemRemove(final RecyclerView.ViewHolder viewHolder, final RecyclerView recyclerView) { final int adapterPosition = viewHolder.getAdapterPosition(); final A removeData = mDataList.get(adapterPosition); mSnackbar = Snackbar .make(recyclerView, R.string.activity_accesslog_remove_date, Snackbar.LENGTH_INDEFINITE) .setAction(R.string.activity_accesslog_undo_remove_date, (View view) -> { mDataList.add(adapterPosition, removeData); notifyItemInserted(adapterPosition); }).addCallback(new Snackbar.Callback() { @Override public void onDismissed(Snackbar snackbar, int event) { // ??? Action ?????????? if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) { if (mOnItemRemoveListener != null) { mOnItemRemoveListener.onItemDelete(removeData); } } } }); mSnackbar.show(); mDataList.remove(adapterPosition); notifyItemRemoved(adapterPosition); } /** * ?????????. * * @param listener */ void setOnItemClickListener(OnItemClickListener listener) { mOnItemClickListener = listener; } /** * ?????????. * * @param listener */ void setOnItemRemoveListener(OnItemRemoveListener<A> listener) { mOnItemRemoveListener = listener; } /** * . */ interface OnItemClickListener { void onItemClick(View view, int position); } /** * . */ interface OnItemRemoveListener<A> { void onItemDelete(A data); } } /** * ???. * */ public static class DateListFragment extends BaseFragment { /** * . */ private static final int REQUEST_CODE = 100; /** * ???. */ private DateListAdapter mListAdapter; /** * DateListFragment ?????. * * @return DateListFragment? */ static DateListFragment create() { return new DateListFragment(); } @SuppressLint("ClickableViewAccessibility") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_accesslog_date_list, container, false); mListAdapter = new DateListAdapter(inflater); mListAdapter.setOnItemClickListener( (v, position) -> gotoAccessLogListFragment(mListAdapter.getItem(position))); mListAdapter.setOnItemRemoveListener((data) -> { AccessLogProvider provider = getAccessLogProvider(); if (provider != null) { provider.remove(data); } }); RecyclerView recyclerView = root.findViewById(R.id.recycler_view_accesslog_date_list); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(mListAdapter); recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL)); recyclerView.setOnTouchListener((v, event) -> { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mListAdapter.dismissSnackbar(); break; } return false; }); ItemTouchHelper helper = new ItemTouchHelper(new SwipeToDeleteCallback(getContext()) { @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mListAdapter.onItemRemove(viewHolder, recyclerView); } }); helper.attachToRecyclerView(recyclerView); setHasOptionsMenu(true); return root; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.fragment_date_list, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.fragment_accesslog_all_delete: new DeleteDialogFragment.Builder().requestCode(REQUEST_CODE) .title(getString(R.string.fragment_accesslog_delete_all_title)) .message(getString(R.string.fragment_accesslog_delete_all_message)) .positive(getString(R.string.fragment_accesslog_delete_all_positive)) .negative(getString(R.string.fragment_accesslog_delete_all_nagetive)) .show(getFragmentManager(), this); break; } return true; } @Override public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { if (requestCode == REQUEST_CODE) { if (resultCode == DialogInterface.BUTTON_POSITIVE) { deleteAll(); } } } @Override public void onResume() { super.onResume(); AccessLogProvider provider = getAccessLogProvider(); if (provider != null) { provider.getDateList(this::updateDateList); } } @Override void onReturn() { mListAdapter.dismissSnackbar(); } /** * ???. * * @param dateList ? */ private void updateDateList(List<String> dateList) { runOnUiThread(() -> { if (dateList.isEmpty()) { setNoDateView(View.VISIBLE); } else { setNoDateView(View.GONE); mListAdapter.updateDataList(dateList); } }); } /** * ??????View????. * * @param visibility */ private void setNoDateView(int visibility) { View root = getView(); if (root != null) { View v = root.findViewById(R.id.fragment_accesslog_no_data); if (v != null) { v.setVisibility(visibility); } } } /** * AccessLogListFragment ???. * * @param date ? */ private void gotoAccessLogListFragment(String date) { gotoFragment(AccessLogListFragment.create(date)); } /** * ???. */ void deleteAll() { AccessLogProvider provider = getAccessLogProvider(); if (provider != null) { provider.removeAll((Boolean value) -> getActivity().finish()); } } } /** * ???. */ private static class DateListAdapter extends BaseAdapter<String, DateListAdapter.ViewHolder> { /** * . * @param inflater */ DateListAdapter(LayoutInflater inflater) { super(inflater); } @Override public DateListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new ViewHolder(mInflater.inflate(R.layout.item_accesslog_date_list, parent, false)); } @Override public void onBindViewHolder(DateListAdapter.ViewHolder holder, int position) { holder.mTextView.setText(mDataList.get(position)); } /** * View ???. */ class ViewHolder extends RecyclerView.ViewHolder { /** * ??View. */ TextView mTextView; /** * . * @param itemView RecyclerView?View */ ViewHolder(View itemView) { super(itemView); mTextView = itemView.findViewById(R.id.accesslog_date_name); itemView.setOnClickListener((v) -> { if (mOnItemClickListener != null) { v.postDelayed(() -> mOnItemClickListener.onItemClick(itemView, getAdapterPosition()), 300); } }); // ?????? Snackbar ??? itemView.setOnTouchListener((v, event) -> { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: dismissSnackbar(); break; } return false; }); } } } /** * ?????. */ public static class AccessLogListFragment extends BaseFragment { /** * . */ private static final int REQUEST_CODE = 101; /** * ???. */ private static final String ARGS_DATE = "date"; /** * ?????. */ private AccessLogListAdapter mListAdapter; /** * . */ private EditText mCondition; /** * AccessLogListFragment ????. * * @param date ?? * @return AccessLogListFragment? */ static AccessLogListFragment create(String date) { Bundle args = new Bundle(); args.putString(ARGS_DATE, date); AccessLogListFragment fragment = new AccessLogListFragment(); fragment.setArguments(args); return fragment; } @SuppressLint("ClickableViewAccessibility") @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_accesslog_list, container, false); mListAdapter = new AccessLogListAdapter(inflater); mListAdapter.setOnItemClickListener( (view, position) -> gotoAccessLogFragment(mListAdapter.getItem(position))); mListAdapter.setOnItemRemoveListener((data) -> { AccessLogProvider provider = getAccessLogProvider(); if (provider != null) { provider.remove(data); } }); mCondition = root.findViewById(R.id.fragment_search_edit_text); RecyclerView recyclerView = root.findViewById(R.id.list_view_accesslog_list); recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setAdapter(mListAdapter); recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL)); recyclerView.setOnTouchListener((v, event) -> { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mListAdapter.dismissSnackbar(); break; } return false; }); ItemTouchHelper helper = new ItemTouchHelper(new SwipeToDeleteCallback(getContext()) { @Override public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { mListAdapter.onItemRemove(viewHolder, recyclerView); } }); helper.attachToRecyclerView(recyclerView); root.findViewById(R.id.fragment_search_btn).setOnClickListener((v) -> { searchAccessLogs(mCondition.getText().toString()); InputMethodManager imm = (InputMethodManager) getContext() .getSystemService(Context.INPUT_METHOD_SERVICE); if (imm != null) { imm.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); } }); setHasOptionsMenu(true); return root; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); inflater.inflate(R.menu.fragment_date_list, menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.fragment_accesslog_all_delete: new DeleteDialogFragment.Builder().requestCode(REQUEST_CODE) .title(getString(R.string.fragment_accesslog_delete_accesslog_title)) .message(getString(R.string.fragment_accesslog_delete_accesslog_message, getDateString())) .positive(getString(R.string.fragment_accesslog_delete_accesslog_positive)) .negative(getString(R.string.fragment_accesslog_delete_accesslog_negative)) .show(getFragmentManager(), this); break; } return true; } @Override public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { if (requestCode == REQUEST_CODE) { if (resultCode == DialogInterface.BUTTON_POSITIVE) { deleteAccessLogs(); } } } @Override public void onResume() { super.onResume(); searchAccessLogs(mCondition.getText().toString()); } @Override void onReturn() { mListAdapter.dismissSnackbar(); } /** * ???????. * <p> * ?????????? null ??? * </p> * @return */ private String getDateString() { Bundle args = getArguments(); if (args != null) { return args.getString(ARGS_DATE); } return null; } /** * ????????. */ private void deleteAccessLogs() { String date = getDateString(); AccessLogProvider provider = getAccessLogProvider(); if (date != null && provider != null) { provider.remove(date, (value) -> popFragment()); } } /** * ????. * * @param accessLogList ? */ private void updateAccessLogList(List<AccessLog> accessLogList) { runOnUiThread(() -> { if (accessLogList.isEmpty()) { setNoDateView(View.VISIBLE); } else { setNoDateView(View.GONE); mListAdapter.updateDataList(accessLogList); } }); } /** * ????????. * * @param condition ? */ private void searchAccessLogs(String condition) { mListAdapter.dismissSnackbar(); String date = getDateString(); AccessLogProvider provider = getAccessLogProvider(); if (provider != null && date != null) { if (condition == null || condition.isEmpty()) { provider.getAccessLogsOfDate(date, this::updateAccessLogList); } else { provider.getAccessLogsFromCondition(date, condition, this::updateAccessLogList); } } } /** * ??????View????. * * @param visibility */ private void setNoDateView(int visibility) { View root = getView(); if (root != null) { View v = root.findViewById(R.id.fragment_accesslog_no_data); if (v != null) { v.setVisibility(visibility); } } } /** * ??????. * * @param accessLog */ private void gotoAccessLogFragment(AccessLog accessLog) { gotoFragment(AccessLogFragment.create(accessLog.getId())); } } /** * ???. */ private static class AccessLogListAdapter extends BaseAdapter<AccessLog, AccessLogListAdapter.ViewHolder> { AccessLogListAdapter(LayoutInflater inflater) { super(inflater); } private static final Object[][] METHOD_COLORS = { { "get", R.drawable.access_log_method_get }, { "put", R.drawable.access_log_method_put }, { "post", R.drawable.access_log_method_post }, { "delete", R.drawable.access_log_method_delete }, }; @Override public AccessLogListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new ViewHolder(mInflater.inflate(R.layout.item_accesslog_list, parent, false)); } @Override public void onBindViewHolder(AccessLogListAdapter.ViewHolder holder, int position) { AccessLog accessLog = mDataList.get(position); holder.mIpAddress.setText(getIpAddress(accessLog)); holder.mPath.setText(getPath(accessLog)); holder.mDate.setText(getDate(accessLog)); String method = accessLog.getRequestMethod(); for (Object[] v : METHOD_COLORS) { String m = (String) v[0]; if (m.equalsIgnoreCase(method)) { holder.mMethod.setBackgroundResource((int) v[1]); } } holder.mMethod.setText(method); } /** * View ???. */ class ViewHolder extends RecyclerView.ViewHolder { /** * IP?TextView. */ TextView mIpAddress; /** * ?TextView. */ TextView mMethod; /** * ?TextView. */ TextView mPath; /** * ?TextView. */ TextView mDate; /** * . * @param itemView RecyclerView?View */ ViewHolder(View itemView) { super(itemView); mIpAddress = itemView.findViewById(R.id.item_access_log_ip_address); mMethod = itemView.findViewById(R.id.item_access_log_method); mPath = itemView.findViewById(R.id.item_access_log_path); mDate = itemView.findViewById(R.id.item_access_log_date); itemView.setOnClickListener((v) -> { if (mOnItemClickListener != null) { v.postDelayed(() -> mOnItemClickListener.onItemClick(itemView, getAdapterPosition()), 300); } }); // ?????? Snackbar ??? itemView.setOnTouchListener((v, event) -> { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: dismissSnackbar(); break; } return false; }); } } /** * ? IP ????. * * @param accessLog * @return IP */ private String getIpAddress(AccessLog accessLog) { String ipAddress = accessLog.getRemoteIpAddress(); if (ipAddress == null) { ipAddress = "none"; } return ipAddress; } /** * ?HTTP?????. * * @param accessLog * @return HTTP? */ private String getPath(AccessLog accessLog) { String path = accessLog.getRequestPath(); if (path == null) { path = "/"; } return path; } /** * ??????. * * @param accessLog * @return ? */ private String getDate(AccessLog accessLog) { return AccessLogProvider.dateToString(accessLog.getRequestReceivedTime()); } } /** * ??. */ public static class AccessLogFragment extends BaseFragment { /** * ?ID??. */ private static final String ARGS_ID = "id"; /** * ??TextView. */ private TextView mRequestView; /** * ???TextView. */ private TextView mResponseView; /** * ????TextView. */ private TextView mRequestTimeView; /** * ??IP?TextView. */ private TextView mIpAddressView; /** * ?????TextView. */ private TextView mHostNameView; /** * ?????TextView. */ private TextView mSendTimeView; /** * AccessLogFragment ????. * * @param id ?ID * @return AccessLogFragment? */ static AccessLogFragment create(long id) { Bundle args = new Bundle(); args.putLong(ARGS_ID, id); AccessLogFragment fragment = new AccessLogFragment(); fragment.setArguments(args); return fragment; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_accesslog_detail, container, false); mRequestView = root.findViewById(R.id.fragment_accesslog_detail_request); mRequestTimeView = root.findViewById(R.id.fragment_accesslog_detail_request_time); mIpAddressView = root.findViewById(R.id.fragment_accesslog_detail_request_ip_address); mHostNameView = root.findViewById(R.id.fragment_accesslog_detail_request_host_name); mResponseView = root.findViewById(R.id.fragment_accesslog_detail_response); mSendTimeView = root.findViewById(R.id.fragment_accesslog_detail_response_time); return root; } @Override public void onResume() { super.onResume(); long id = getAccessLogId(); AccessLogProvider provider = getAccessLogProvider(); if (provider != null && id != -1) { provider.getAccessLog(id, this::updateAccessLog); } } /** * ????. * * @param accessLog */ private void updateAccessLog(AccessLog accessLog) { if (accessLog == null) { return; } updateAccessLog(AccessLogProvider.dateToString(accessLog.getRequestReceivedTime()), AccessLogProvider.dateToString(accessLog.getResponseSendTime()), accessLog.getRemoteIpAddress(), accessLog.getRemoteHostName(), createRequestString(accessLog), createResponseString(accessLog)); } /** * ??????. * * @param accessLog * @return ? */ private String createRequestString(AccessLog accessLog) { StringBuilder request = new StringBuilder(); request.append(accessLog.getRequestMethod()).append(" ").append(accessLog.getRequestPath()) .append("\r\n"); Map<String, String> headers = accessLog.getRequestHeader(); if (headers != null) { for (String key : headers.keySet()) { request.append(key).append(": ").append(headers.get(key)).append("\r\n"); } } if (accessLog.getRequestBody() != null) { request.append("\r\n"); request.append(accessLog.getRequestBody()).append("\r\n"); } return request.toString(); } /** * ???????. * * @param accessLog * @return ? */ private String createResponseString(AccessLog accessLog) { StringBuilder response = new StringBuilder(); response.append("HTTP/1.1 ").append(accessLog.getResponseStatusCode()).append("\r\n"); if (accessLog.getResponseContentType() != null) { response.append("Content-Type: ").append(accessLog.getResponseContentType()).append("\r\n"); } response.append("\r\n"); if (accessLog.getResponseBody() != null) { if (isContentType(accessLog.getResponseContentType())) { response.append(reshapeJson(accessLog.getResponseBody())).append("\r\n"); } else { response.append(accessLog.getResponseBody()).append("\r\n"); } } return response.toString(); } /** * ? TextView ??????. * * @param receivedTime ? * @param sendTime ? * @param ipAddress IP * @param hostName ?? * @param request * @param response ? */ private void updateAccessLog(String receivedTime, String sendTime, String ipAddress, String hostName, String request, String response) { runOnUiThread(() -> { mRequestTimeView.setText(receivedTime); mSendTimeView.setText(sendTime); mIpAddressView.setText(ipAddress); mHostNameView.setText(hostName); mRequestView.setText(request); mResponseView.setText(response); }); } /** * ?JSON?????. * * @param contentType * @return JSON????true????false */ private boolean isContentType(String contentType) { return contentType != null && contentType.startsWith("application/json"); } /** * JSON???????. * * @param body JSON? * @return ??JSON? */ private String reshapeJson(String body) { try { JSONObject object = new JSONObject(body); return object.toString(2); } catch (JSONException e) { return body; } } /** * ????ID????. * * @return ?ID */ private long getAccessLogId() { Bundle args = getArguments(); if (args != null) { return args.getLong(ARGS_ID); } return -1; } } /** * ??. */ public static class DeleteDialogFragment extends DialogFragment { /** * ?. */ private final DialogInterface.OnClickListener mOnClickListener = (dialog, id) -> { dismiss(); Fragment targetFragment = getTargetFragment(); if (targetFragment != null) { targetFragment.onActivityResult(getTargetRequestCode(), id, null); } }; @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { String title = getArguments().getString("title"); String message = getArguments().getString("message"); String positive = getArguments().getString("positive"); String negative = getArguments().getString("negative"); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); if (title != null) { builder.setTitle(title); } if (message != null) { builder.setMessage(message); } builder.setPositiveButton(positive, mOnClickListener); if (negative != null) { builder.setNegativeButton(negative, mOnClickListener); } return builder.create(); } /** * ?. */ public static class Builder { /** * ?. */ private String mTitle; /** * ?. */ private String mMessage; /** * ? Positive ?. */ private String mPositive; /** * ? Negative ?. */ private String mNegative; /** * . */ private int mRequestCode; /** * ???. * * @param requestCode * @return Builder */ Builder requestCode(int requestCode) { mRequestCode = requestCode; return this; } /** * ???. * * @param title * @return Builder */ Builder title(String title) { mTitle = title; return this; } /** * ???. * * @param message * @return Builder */ Builder message(String message) { mMessage = message; return this; } /** * Positive ????. * * @param positive Positive ? * @return Builder */ Builder positive(String positive) { mPositive = positive; return this; } /** * Negative ????. * * @param negative negative ? * @return Builder */ Builder negative(String negative) { mNegative = negative; return this; } /** * ???. * <p> * targetFragment ??? Fragment ? {@link Fragment#onActivityResult(int, int, Intent)} * ?????? * </p> * @param fragmentManager ?FragmentManager * @param targetFragment ??Fragment */ void show(FragmentManager fragmentManager, Fragment targetFragment) { Bundle bundle = new Bundle(); if (mTitle != null) { bundle.putString("title", mTitle); } if (mMessage != null) { bundle.putString("message", mMessage); } if (mPositive != null) { bundle.putString("positive", mPositive); } if (mNegative != null) { bundle.putString("negative", mNegative); } DialogFragment dialog = new DeleteDialogFragment(); dialog.setArguments(bundle); dialog.setTargetFragment(targetFragment, mRequestCode); dialog.show(fragmentManager, "test"); } } } /** * RecyclerView ?. */ private static abstract class SwipeToDeleteCallback extends ItemTouchHelper.SimpleCallback { /** * ?. */ private Drawable mDeleteIcon; /** * . */ private ColorDrawable mBackground; /** * . * @param context */ SwipeToDeleteCallback(Context context) { super(0, (ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT)); mDeleteIcon = ContextCompat.getDrawable(context, android.R.drawable.ic_menu_delete); mBackground = new ColorDrawable(Color.rgb(235, 55, 35)); } @Override public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { return false; } @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dx, float dy, int actionState, boolean isCurrentlyActive) { View itemView = viewHolder.itemView; int backgroundCornerOffset = 20; int iconMargin = (itemView.getHeight() - mDeleteIcon.getIntrinsicHeight()) / 2; int iconTop = itemView.getTop() + (itemView.getHeight() - mDeleteIcon.getIntrinsicHeight()) / 2; int iconBottom = iconTop + mDeleteIcon.getIntrinsicHeight(); if (dx > 0) { // Swiping to the right int iconLeft = itemView.getLeft() + iconMargin + mDeleteIcon.getIntrinsicWidth(); int iconRight = itemView.getLeft() + iconMargin; mDeleteIcon.setBounds(iconLeft, iconTop, iconRight, iconBottom); mBackground.setBounds(itemView.getLeft(), itemView.getTop(), itemView.getLeft() + ((int) dx) + backgroundCornerOffset, itemView.getBottom()); } else if (dx < 0) { // Swiping to the left int iconLeft = itemView.getRight() - iconMargin - mDeleteIcon.getIntrinsicWidth(); int iconRight = itemView.getRight() - iconMargin; mDeleteIcon.setBounds(iconLeft, iconTop, iconRight, iconBottom); mBackground.setBounds(itemView.getRight() + ((int) dx) - backgroundCornerOffset, itemView.getTop(), itemView.getRight(), itemView.getBottom()); } else { // view is unSwiped mBackground.setBounds(0, 0, 0, 0); } mBackground.draw(c); mDeleteIcon.draw(c); super.onChildDraw(c, recyclerView, viewHolder, dx, dy, actionState, isCurrentlyActive); } } }