Support writing of wav-file also in Android 10

pull/3/head
Olga Miller 2020-06-22 23:33:26 +02:00
rodzic 4fc704604b
commit d452255b62
8 zmienionych plików z 135 dodań i 62 usunięć

Wyświetl plik

@ -3,7 +3,8 @@
package="om.sstvencoder">
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28"/>
<uses-feature
android:name="android.hardware.camera"
android:required="false"/>

Wyświetl plik

@ -17,7 +17,6 @@ package om.sstvencoder;
import android.graphics.Bitmap;
import java.io.File;
import java.util.LinkedList;
import java.util.List;
@ -26,6 +25,7 @@ import om.sstvencoder.ModeInterfaces.IModeInfo;
import om.sstvencoder.Modes.ModeFactory;
import om.sstvencoder.Output.IOutput;
import om.sstvencoder.Output.OutputFactory;
import om.sstvencoder.Output.WaveFileOutputContext;
// Creates IMode instance
class Encoder {
@ -108,21 +108,21 @@ class Encoder {
enqueue(mode);
}
void save(Bitmap bitmap, File file) {
void save(Bitmap bitmap, WaveFileOutputContext context) {
if (mSaveWaveThread != null && mSaveWaveThread.isAlive())
return;
IOutput output = OutputFactory.createOutputForSavingAsWave(file);
IOutput output = OutputFactory.createOutputForSavingAsWave(context);
IMode mode = ModeFactory.CreateMode(mModeClass, bitmap, output);
if (mode != null)
save(mode, file);
save(mode, context);
}
private void save(final IMode mode, final File file) {
private void save(final IMode mode, final WaveFileOutputContext context) {
mSaveWaveThread = new Thread() {
@Override
public void run() {
mode.init();
mProgressBar2.begin(mode.getProcessCount(), file.getName() + " saving...");
mProgressBar2.begin(mode.getProcessCount(), context.getFileName() + " saving...");
while (mode.process()) {
mProgressBar2.step();
@ -135,7 +135,7 @@ class Encoder {
mode.finish(mQuit);
mProgressBar2.end();
if (!mQuit)
mMessenger.carrySaveAsWaveIsDoneMessage(file);
mMessenger.carrySaveAsWaveIsDoneMessage(context);
}
};
mSaveWaveThread.start();

Wyświetl plik

@ -19,7 +19,6 @@ import android.Manifest;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
@ -43,10 +42,10 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.InputStream;
import om.sstvencoder.ModeInterfaces.IModeInfo;
import om.sstvencoder.Output.WaveFileOutputContext;
import om.sstvencoder.TextOverlay.Label;
public class MainActivity extends AppCompatActivity {
@ -191,7 +190,8 @@ public class MainActivity extends AppCompatActivity {
}
private boolean needsRequestWritePermission() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return false;
String permission = Manifest.permission.WRITE_EXTERNAL_STORAGE;
int state = ContextCompat.checkSelfPermission(this, permission);
@ -443,18 +443,15 @@ public class MainActivity extends AppCompatActivity {
}
private void save() {
File file = Utility.createWaveFilePath();
mEncoder.save(mCropView.getBitmap(), file);
if (Utility.isExternalStorageWritable()) {
WaveFileOutputContext context
= new WaveFileOutputContext(getContentResolver(), Utility.createWaveFileName());
mEncoder.save(mCropView.getBitmap(), context);
}
}
public void completeSaving(File file) {
addFileToContentResolver(file);
}
private void addFileToContentResolver(File file) {
ContentValues values = Utility.getWavContentValues(file);
Uri uri = MediaStore.Audio.Media.getContentUriForPath(file.getAbsolutePath());
getContentResolver().insert(uri, values);
public void completeSaving(WaveFileOutputContext context) {
context.clear();
}
@Override

Wyświetl plik

@ -17,7 +17,7 @@ package om.sstvencoder;
import android.os.Handler;
import java.io.File;
import om.sstvencoder.Output.WaveFileOutputContext;
class MainActivityMessenger {
private final MainActivity mMainActivity;
@ -28,11 +28,11 @@ class MainActivityMessenger {
mHandler = new Handler();
}
void carrySaveAsWaveIsDoneMessage(final File file) {
void carrySaveAsWaveIsDoneMessage(final WaveFileOutputContext context) {
mHandler.post(new Runnable() {
@Override
public void run() {
mMainActivity.completeSaving(file);
mMainActivity.completeSaving(context);
}
});
}

Wyświetl plik

@ -15,8 +15,6 @@ limitations under the License.
*/
package om.sstvencoder.Output;
import java.io.File;
public final class OutputFactory {
public static IOutput createOutputForSending() {
@ -24,11 +22,8 @@ public final class OutputFactory {
return new AudioOutput(sampleRate);
}
public static IOutput createOutputForSavingAsWave(File filePath) {
public static IOutput createOutputForSavingAsWave(WaveFileOutputContext context) {
double sampleRate = 44100.0;
if (filePath == null)
return null;
return new WaveFileOutput(filePath, sampleRate);
return new WaveFileOutput(context, sampleRate);
}
}

Wyświetl plik

@ -16,17 +16,15 @@ limitations under the License.
package om.sstvencoder.Output;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
class WaveFileOutput implements IOutput {
private final double mSampleRate;
private File mFile;
private WaveFileOutputContext mContext;
private BufferedOutputStream mOutputStream;
private int mSamples, mWrittenSamples;
WaveFileOutput(File file, double sampleRate) {
mFile = file;
WaveFileOutput(WaveFileOutputContext context, double sampleRate) {
mContext = context;
mSampleRate = sampleRate;
}
@ -67,7 +65,7 @@ class WaveFileOutput implements IOutput {
private void InitOutputStream() {
try {
mOutputStream = new BufferedOutputStream(new FileOutputStream(mFile));
mOutputStream = new BufferedOutputStream(mContext.createWaveOutputStream());
} catch (Exception ignore) {
}
}
@ -98,11 +96,8 @@ class WaveFileOutput implements IOutput {
} catch (Exception ignore) {
}
if (mFile != null) {
if (cancel)
mFile.delete();
mFile = null;
}
if (cancel)
mContext.deleteFile();
}
private void padWithZeros(int count) {

Wyświetl plik

@ -0,0 +1,101 @@
/*
Copyright 2020 Olga Miller <olga.rgb@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package om.sstvencoder.Output;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class WaveFileOutputContext {
private ContentResolver mContentResolver;
private String mFileName;
private File mFile;
private Uri mUri;
private ContentValues mValues;
public WaveFileOutputContext(ContentResolver contentResolver, String fileName) {
mContentResolver = contentResolver;
mFileName = fileName;
}
public String getFileName() {
return mFileName;
}
public OutputStream createWaveOutputStream() {
if (init()) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
return mContentResolver.openOutputStream(mUri);
else
return new FileOutputStream(mFile);
} catch (Exception ignore) {
}
}
return null;
}
private boolean init() {
String album = "SSTV Encoder";
mValues = new ContentValues();
mValues.put(MediaStore.Audio.Media.ALBUM, album);
mValues.put(MediaStore.Audio.Media.MIME_TYPE, "audio/wav");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
mValues.put(MediaStore.Audio.Media.DISPLAY_NAME, mFileName);
mValues.put(MediaStore.Audio.Media.RELATIVE_PATH, (new File(Environment.DIRECTORY_MUSIC, album)).getPath());
mValues.put(MediaStore.Audio.Media.IS_PENDING, 1);
mUri = mContentResolver.insert(MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY), mValues);
if (mUri != null) {
String path = mUri.getPath();
if (path != null)
mFile = new File(path);
}
} else {
mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC), mFileName);
mValues.put(MediaStore.Audio.Media.DATA, mFile.toString());
mValues.put(MediaStore.Audio.Media.TITLE, mFileName);
mValues.put(MediaStore.Audio.Media.IS_MUSIC, true);
mUri = MediaStore.Audio.Media.getContentUriForPath(mFile.getAbsolutePath());
if (mUri != null)
mContentResolver.insert(mUri, mValues);
}
return mUri != null;
}
public void clear() {
if (mUri != null && mValues != null) {
mValues.clear();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
mValues.put(MediaStore.Audio.Media.IS_PENDING, 0);
mContentResolver.update(mUri, mValues, null, null);
}
}
public void deleteFile() {
try {
if (mFile != null)
mFile.delete();
} catch (Exception ignore) {
}
}
}

Wyświetl plik

@ -15,7 +15,6 @@ limitations under the License.
*/
package om.sstvencoder;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
@ -23,7 +22,7 @@ import androidx.exifinterface.media.ExifInterface;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import androidx.annotation.NonNull;
import androidx.core.content.FileProvider;
@ -89,18 +88,6 @@ final class Utility {
return 0;
}
@NonNull
static ContentValues getWavContentValues(File file) {
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Media.ALBUM, "SSTV Encoder");
values.put(MediaStore.Audio.Media.ARTIST, "");
values.put(MediaStore.Audio.Media.DATA, file.toString());
values.put(MediaStore.Audio.Media.IS_MUSIC, true);
values.put(MediaStore.Audio.Media.MIME_TYPE, "audio/wav");
values.put(MediaStore.Audio.Media.TITLE, file.getName());
return values;
}
static Uri createImageUri(Context context) {
if (!isExternalStorageWritable())
return null;
@ -114,18 +101,15 @@ final class Utility {
return FileProvider.getUriForFile(context, "om.sstvencoder", file); // content:// URI
}
static File createWaveFilePath() {
if (!isExternalStorageWritable())
return null;
File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC);
return new File(dir, createFileName() + ".wav");
static String createWaveFileName() {
return createFileName() + ".wav";
}
private static String createFileName() {
return new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
}
private static boolean isExternalStorageWritable() {
static boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
return Environment.MEDIA_MOUNTED.equals(state);
}