Save files to external storage

This commit is contained in:
William Brawner 2017-07-27 18:21:26 -05:00
parent 9a493fb536
commit 74a6f930a5
5 changed files with 111 additions and 37 deletions

View file

@ -6,8 +6,10 @@ import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.FileProvider; import android.support.v4.content.FileProvider;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.text.Editable; import android.text.Editable;
@ -18,6 +20,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Toast;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@ -34,11 +37,12 @@ public class EditFragment extends Fragment {
public static final String SAVE_ACTION = "com.wbrawner.simplemarkdown.ACTION_SAVE"; public static final String SAVE_ACTION = "com.wbrawner.simplemarkdown.ACTION_SAVE";
public static final String LOAD_ACTION = "com.wbrawner.simplemarkdown.ACTION_LOAD"; public static final String LOAD_ACTION = "com.wbrawner.simplemarkdown.ACTION_LOAD";
private static EditText mMarkdownEditor; private static EditText mMarkdownEditor;
private FileUtils mFileUtils;
@BindView(R.id.markdown_edit) @BindView(R.id.markdown_edit)
EditText markdownEditor; EditText markdownEditor;
private Context mContext; private FragmentActivity mContext;
private File mTmpFile; private File mTmpFile;
private boolean loadTmpFile = true; private boolean loadTmpFile = true;
@ -58,6 +62,7 @@ public class EditFragment extends Fragment {
filter filter
); );
mContext = getActivity(); mContext = getActivity();
mFileUtils = new FileUtils(mContext);
} }
@Override @Override
@ -111,10 +116,16 @@ public class EditFragment extends Fragment {
public void save(String data, String filePath) { public void save(String data, String filePath) {
// TODO: move this to AsyncTask // TODO: move this to AsyncTask
if (filePath == null) if (!mFileUtils.isExternalStorageWriteable()) {
mFileUtils.requestWritePermissions();
return;
}
if (filePath == null) {
filePath = MainActivity.getFilePath() + MainActivity.getFileName(); filePath = MainActivity.getFilePath() + MainActivity.getFileName();
}
FileOutputStream out = null; FileOutputStream out = null;
try { try {
Log.d(TAG, "File path: " + filePath);
File tmpFile = new File(filePath); File tmpFile = new File(filePath);
out = new FileOutputStream(tmpFile); out = new FileOutputStream(tmpFile);
out.write(data.getBytes()); out.write(data.getBytes());
@ -122,8 +133,11 @@ public class EditFragment extends Fragment {
Log.e(TAG, "Error saving temp file:", e); Log.e(TAG, "Error saving temp file:", e);
} finally { } finally {
try { try {
if (out != null) if (out != null) {
out.close(); out.close();
Toast.makeText(mContext, getString(R.string.file_saved, filePath), Toast.LENGTH_SHORT)
.show();
}
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Error closing write stream", e); Log.e(TAG, "Error closing write stream", e);
} }
@ -134,8 +148,8 @@ public class EditFragment extends Fragment {
save(data, null); save(data, null);
} }
public void save(Editable data) { public void save() {
save(data.toString(), null); save(mMarkdownEditor.getText().toString(), null);
} }
@Override @Override
@ -157,6 +171,11 @@ public class EditFragment extends Fragment {
case SAVE_ACTION: case SAVE_ACTION:
if (intent.hasExtra("fileName")) { if (intent.hasExtra("fileName")) {
String fileName = intent.getStringExtra("fileName"); String fileName = intent.getStringExtra("fileName");
if (!fileName.contains("/")) {
fileName = MainActivity.getFilePath() + "/" + fileName;
}
if (!fileName.endsWith(".md"))
fileName += ".md";
save(mMarkdownEditor.getText().toString(), fileName); save(mMarkdownEditor.getText().toString(), fileName);
} }
break; break;

View file

@ -0,0 +1,64 @@
package com.wbrawner.simplemarkdown;
import android.Manifest;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
/**
* Created by billy on 7/27/2017.
*/
public class FileUtils {
public static final int WRITE_PERMISSION_REQUEST = 0;
private Activity mContext;
public FileUtils(Activity context) {
mContext = context;
}
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
public boolean isExternalStorageWriteable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) && checkWritePermission()) {
return true;
}
return false;
}
public boolean checkWritePermission() {
return (ContextCompat.checkSelfPermission(
mContext,
Manifest.permission.WRITE_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED);
}
public void requestWritePermissions() {
ActivityCompat.requestPermissions(
mContext,
new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE},
WRITE_PERMISSION_REQUEST
);
}
}

View file

@ -8,6 +8,8 @@ import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout; import android.support.design.widget.TabLayout;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
@ -16,14 +18,17 @@ import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.content.ContextCompat; import android.support.v4.content.ContextCompat;
import android.support.v4.content.FileProvider; import android.support.v4.content.FileProvider;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.os.EnvironmentCompat;
import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable;
import android.text.InputType; import android.text.InputType;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.SearchEvent;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Toast; import android.widget.Toast;
@ -33,7 +38,8 @@ import java.io.File;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity
implements ActivityCompat.OnRequestPermissionsResultCallback {
public static final String AUTHORITY = "com.wbrawner.simplemarkdown.fileprovider"; public static final String AUTHORITY = "com.wbrawner.simplemarkdown.fileprovider";
private static final int REQUEST_WRITE_STORAGE = 0; private static final int REQUEST_WRITE_STORAGE = 0;
@ -43,6 +49,7 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = MainActivity.class.getSimpleName(); private static final String TAG = MainActivity.class.getSimpleName();
private static String fileName; private static String fileName;
public static FileUtils mFileUtils;
public static String getTempFileName() { public static String getTempFileName() {
return "tmp_" + getFileName(); return "tmp_" + getFileName();
@ -62,7 +69,7 @@ public class MainActivity extends AppCompatActivity {
} }
public static String getFilePath() { public static String getFilePath() {
return mFilesDir + "/saved_files/"; return Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + "/";
} }
public static void setFileName(String fileName) { public static void setFileName(String fileName) {
@ -123,10 +130,7 @@ public class MainActivity extends AppCompatActivity {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if (input.getText().length() > 0) { if (input.getText().length() > 0) {
setFileName(input.getText().toString()); setFileName(input.getText().toString());
Intent saveIntent = new Intent(EditFragment.SAVE_ACTION); requestSave(input.getText().toString());
saveIntent.putExtra("fileName", input.getText());
LocalBroadcastManager.getInstance(getApplicationContext())
.sendBroadcast(saveIntent);
} }
} }
}); });
@ -148,11 +152,8 @@ public class MainActivity extends AppCompatActivity {
LocalBroadcastManager.getInstance(getApplicationContext()) LocalBroadcastManager.getInstance(getApplicationContext())
.sendBroadcast(saveIntent); .sendBroadcast(saveIntent);
} }
Log.d(TAG, "Temp file size: " + tmpFile.length());
Uri fileUri = FileProvider.getUriForFile(MainActivity.this, AUTHORITY, tmpFile); Uri fileUri = FileProvider.getUriForFile(MainActivity.this, AUTHORITY, tmpFile);
// Uri fileUri = Uri.fromFile(tmpFile);
if (fileUri != null) { if (fileUri != null) {
Log.d(TAG, "MIME type: " + getContentResolver().getType(fileUri));
try { try {
Intent shareIntent = new Intent(Intent.ACTION_SEND); Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setDataAndType( shareIntent.setDataAndType(
@ -177,33 +178,31 @@ public class MainActivity extends AppCompatActivity {
} }
} }
break; break;
// case R.id.action_export:
// //TODO: Implement export functionality
// if (ContextCompat.checkSelfPermission(MainActivity.this,
// Manifest.permission.WRITE_EXTERNAL_STORAGE)
// != PackageManager.PERMISSION_GRANTED){
// ActivityCompat.requestPermissions(MainActivity.this,
// new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
// REQUEST_WRITE_STORAGE);
// break;
// }
} }
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
private void requestSave(String text) {
Intent saveIntent = new Intent(EditFragment.SAVE_ACTION);
saveIntent.putExtra("fileName", text);
LocalBroadcastManager.getInstance(getApplicationContext())
.sendBroadcast(saveIntent);
}
@Override @Override
public void onRequestPermissionsResult(int requestCode, public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) { String permissions[], int[] grantResults) {
//TODO: Implement export functionality
switch (requestCode) { switch (requestCode) {
case REQUEST_WRITE_STORAGE: { case FileUtils.WRITE_PERMISSION_REQUEST: {
// If request is cancelled, the result arrays are empty. // If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) { && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted, open file chooser dialog // Permission granted, open file chooser dialog
requestSave(getFileName());
} else { } else {
// Permission denied, do nothing // Permission denied, do nothing
Toast.makeText(MainActivity.this, R.string.no_permissions, Toast.LENGTH_SHORT)
.show();
} }
return; return;
} }

View file

@ -11,16 +11,6 @@
android:id="@+id/action_share" android:id="@+id/action_share"
android:icon="@android:drawable/ic_menu_share" android:icon="@android:drawable/ic_menu_share"
app:showAsAction="always" /> app:showAsAction="always" />
<!--<item-->
<!--android:id="@+id/action_export"-->
<!--android:orderInCategory="100"-->
<!--android:title="@string/action_export"-->
<!--app:showAsAction="never" />-->
<!--<item-->
<!--android:id="@+id/action_settings"-->
<!--android:orderInCategory="100"-->
<!--android:title="@string/action_settings"-->
<!--app:showAsAction="never" />-->
<!--<item--> <!--<item-->
<!--android:id="@+id/action_help"--> <!--android:id="@+id/action_help"-->
<!--android:orderInCategory="100"--> <!--android:orderInCategory="100"-->

View file

@ -14,4 +14,6 @@
<string name="action_export">Export</string> <string name="action_export">Export</string>
<string name="no_shareable_apps">Unable to share file - no capable apps installed</string> <string name="no_shareable_apps">Unable to share file - no capable apps installed</string>
<string name="share_file">Share file to...</string> <string name="share_file">Share file to...</string>
<string name="no_permissions">Unable to save file without permissions</string>
<string name="file_saved">File saved to %1$s</string>
</resources> </resources>