diff --git a/gander/src/main/AndroidManifest.xml b/gander/src/main/AndroidManifest.xml index c9e458c..d822760 100644 --- a/gander/src/main/AndroidManifest.xml +++ b/gander/src/main/AndroidManifest.xml @@ -21,6 +21,17 @@ android:name=".internal.ui.details.TransactionDetailsActivity" android:parentActivityName=".internal.ui.list.TransactionListActivity" android:theme="@style/Gander.Theme" /> + + + + + \ No newline at end of file diff --git a/gander/src/main/java/com/ashokvarma/gander/internal/support/FormatUtils.java b/gander/src/main/java/com/ashokvarma/gander/internal/support/FormatUtils.java index 080a1bb..870f088 100644 --- a/gander/src/main/java/com/ashokvarma/gander/internal/support/FormatUtils.java +++ b/gander/src/main/java/com/ashokvarma/gander/internal/support/FormatUtils.java @@ -1,24 +1,31 @@ package com.ashokvarma.gander.internal.support; import android.content.Context; +import android.net.Uri; +import android.os.Build; import android.text.Spannable; import android.text.SpannableString; -import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.StyleSpan; import androidx.annotation.NonNull; +import androidx.core.content.FileProvider; import com.ashokvarma.gander.R; import com.ashokvarma.gander.internal.data.HttpHeader; import com.ashokvarma.gander.internal.ui.HttpTransactionUIHelper; +import com.ashokvarma.gander.internal.ui.details.TransactionDetailsActivity; import org.json.JSONArray; import org.json.JSONObject; import org.xml.sax.InputSource; +import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; @@ -153,8 +160,21 @@ public static CharSequence formatFormEncoded(String formEncoded) { } } - public static CharSequence getShareText(Context context, HttpTransactionUIHelper transactionUIHelper) { - SpannableStringBuilder text = new SpannableStringBuilder(); + public static CharSequence getShareText(Context context, HttpTransactionUIHelper transactionUIHelper, int position) { + StringBuilder text = new StringBuilder(); + if (position == TransactionDetailsActivity.POSITION_OVERVIEW) { + text.append(getOverviewText(context, transactionUIHelper)); + } else if (position == TransactionDetailsActivity.POSITION_REQUEST) { + text.append(getRequestText(context, transactionUIHelper)); + } else if (position == TransactionDetailsActivity.POSITION_RESPONSE) { + text.append(getResponseText(context, transactionUIHelper)); + } + return text; + } + + @SuppressWarnings("all") + private static CharSequence getOverviewText(Context context, HttpTransactionUIHelper transactionUIHelper) { + StringBuilder text = new StringBuilder(); text.append(context.getString(R.string.gander_url)).append(": ").append(v(transactionUIHelper.getUrl())).append("\n"); text.append(context.getString(R.string.gander_method)).append(": ").append(v(transactionUIHelper.getMethod())).append("\n"); text.append(context.getString(R.string.gander_protocol)).append(": ").append(v(transactionUIHelper.getProtocol())).append("\n"); @@ -170,6 +190,12 @@ public static CharSequence getShareText(Context context, HttpTransactionUIHelper text.append(context.getString(R.string.gander_response_size)).append(": ").append(v(transactionUIHelper.getResponseSizeString())).append("\n"); text.append(context.getString(R.string.gander_total_size)).append(": ").append(v(transactionUIHelper.getTotalSizeString())).append("\n"); text.append("\n"); + return text; + } + + + private static CharSequence getRequestText(Context context, HttpTransactionUIHelper transactionUIHelper) { + StringBuilder text = new StringBuilder(); text.append("---------- ").append(context.getString(R.string.gander_request)).append(" ----------\n\n"); CharSequence headers = formatHeaders(transactionUIHelper.getRequestHeaders(), false); if (!TextUtil.isNullOrWhiteSpace(headers)) { @@ -178,8 +204,14 @@ public static CharSequence getShareText(Context context, HttpTransactionUIHelper text.append((transactionUIHelper.requestBodyIsPlainText()) ? v(transactionUIHelper.getFormattedRequestBody()) : context.getString(R.string.gander_body_omitted)); text.append("\n\n"); + return text; + } + + private static CharSequence getResponseText(Context context, HttpTransactionUIHelper + transactionUIHelper) { + StringBuilder text = new StringBuilder(); text.append("---------- ").append(context.getString(R.string.gander_response)).append(" ----------\n\n"); - headers = formatHeaders(transactionUIHelper.getResponseHeaders(), false); + CharSequence headers = formatHeaders(transactionUIHelper.getResponseHeaders(), false); if (!TextUtil.isNullOrWhiteSpace(headers)) { text.append(headers).append("\n"); } @@ -188,6 +220,40 @@ public static CharSequence getShareText(Context context, HttpTransactionUIHelper return text; } + public static File getShareFile(Context context, HttpTransactionUIHelper transactionUIHelper) { + File file = new File(context.getCacheDir(), transactionUIHelper.getId() + ".txt"); + StringBuilder text = new StringBuilder(); + text.append(getOverviewText(context, transactionUIHelper)); + text.append(getRequestText(context, transactionUIHelper)); + text.append(getResponseText(context, transactionUIHelper)); + BufferedWriter bw = null; + try { + if (!file.exists() && !file.createNewFile()) { + return null; + } + bw = new BufferedWriter(new FileWriter(file)); + bw.write(text.toString()); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + if (bw != null) { + bw.close(); + } + } catch (IOException ignored) { + } + } + return file; + } + + public static Uri getFileUri(Context context, File file) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + return FileProvider.getUriForFile(context, context.getPackageName() + ".file.path.share", file); + } + return Uri.fromFile(file); + } + public static String getShareCurlCommand(HttpTransactionUIHelper transactionUIHelper) { boolean compressed = false; StringBuilder curlCmd = new StringBuilder("curl"); diff --git a/gander/src/main/java/com/ashokvarma/gander/internal/support/GanderFileProvider.java b/gander/src/main/java/com/ashokvarma/gander/internal/support/GanderFileProvider.java new file mode 100644 index 0000000..bd5671c --- /dev/null +++ b/gander/src/main/java/com/ashokvarma/gander/internal/support/GanderFileProvider.java @@ -0,0 +1,9 @@ +package com.ashokvarma.gander.internal.support; + +import androidx.core.content.FileProvider; + +/** + * Created by ssyijiu on 2020/7/24. + */ +public class GanderFileProvider extends FileProvider { +} diff --git a/gander/src/main/java/com/ashokvarma/gander/internal/ui/details/TransactionDetailsActivity.java b/gander/src/main/java/com/ashokvarma/gander/internal/ui/details/TransactionDetailsActivity.java index 4985081..5683fb2 100644 --- a/gander/src/main/java/com/ashokvarma/gander/internal/ui/details/TransactionDetailsActivity.java +++ b/gander/src/main/java/com/ashokvarma/gander/internal/ui/details/TransactionDetailsActivity.java @@ -2,6 +2,7 @@ import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.view.Menu; @@ -9,6 +10,7 @@ import android.view.View; import android.view.WindowInsets; import android.widget.TextView; +import android.widget.Toast; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; @@ -31,6 +33,7 @@ import com.google.android.material.appbar.AppBarLayout; import com.google.android.material.tabs.TabLayout; +import java.io.File; import java.util.ArrayList; import java.util.List; @@ -46,6 +49,11 @@ public class TransactionDetailsActivity extends BaseGanderActivity { private static final String ARG_TRANSACTION_ID = "transaction_id"; private static final String ARG_TRANSACTION_STATUS = "transaction_status"; private static final String ARG_TRANSACTION_RESPONSE_CODE = "transaction_response_code"; + + public static final int POSITION_OVERVIEW = 0; + public static final int POSITION_REQUEST = 1; + public static final int POSITION_RESPONSE = 2; + private static int SELECTED_TAB_POSITION = POSITION_OVERVIEW; public static void start(Context context, long transactionId, HttpTransactionUIHelper.Status status, Integer responseCode) { Intent intent = new Intent(context, TransactionDetailsActivity.class); @@ -55,8 +63,6 @@ public static void start(Context context, long transactionId, HttpTransactionUIH context.startActivity(intent); } - private static int SELECTED_TAB_POSITION = 0; - private TextView mTitleView; private Adapter mAdapter; private AppBarLayout mAppBarLayout; @@ -122,13 +128,23 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == R.id.share_text) { if (mTransaction != null) - share(FormatUtils.getShareText(this, mTransaction)); + share(FormatUtils.getShareText(this, mTransaction, SELECTED_TAB_POSITION)); return true; } else if (item.getItemId() == R.id.share_curl) { if (mTransaction != null) share(FormatUtils.getShareCurlCommand(mTransaction)); return true; - } else { + } else if (item.getItemId() == R.id.share_file) { + if (mTransaction != null) { + File file = FormatUtils.getShareFile(this, mTransaction); + if (file != null) { + shareFile(file); + } else { + Toast.makeText(this, R.string.gander_failed_to_write_file, Toast.LENGTH_SHORT).show(); + } + } + return true; + }else { return super.onOptionsItemSelected(item); } } @@ -166,6 +182,16 @@ private void share(CharSequence content) { startActivity(Intent.createChooser(sendIntent, null)); } + private void shareFile(File file) { + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.setType("text/plain"); + sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + Uri uri = FormatUtils.getFileUri(this, file); + sendIntent.putExtra(Intent.EXTRA_STREAM, uri); + startActivity(Intent.createChooser(sendIntent, null)); + } + static class Adapter extends FragmentPagerAdapter { final List fragments = new ArrayList<>(); private final List fragmentTitles = new ArrayList<>(); diff --git a/gander/src/main/res/menu/gander_details_menu.xml b/gander/src/main/res/menu/gander_details_menu.xml index 8cd37e9..5231a55 100644 --- a/gander/src/main/res/menu/gander_details_menu.xml +++ b/gander/src/main/res/menu/gander_details_menu.xml @@ -10,6 +10,9 @@ + diff --git a/gander/src/main/res/values/strings.xml b/gander/src/main/res/values/strings.xml index 16f0d4a..cc24458 100644 --- a/gander/src/main/res/values/strings.xml +++ b/gander/src/main/res/values/strings.xml @@ -25,6 +25,7 @@ No Share Share as text + Share as file Share as curl command (encoded or binary body omitted) Search @@ -33,4 +34,5 @@ Gander HTTP notifications Search Request and Headers Search Response and Headers + "Failed to write file" diff --git a/gander/src/main/res/xml/gander_file_paths.xml b/gander/src/main/res/xml/gander_file_paths.xml new file mode 100644 index 0000000..a5596a9 --- /dev/null +++ b/gander/src/main/res/xml/gander_file_paths.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + \ No newline at end of file