mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Make Huawei AudioInfo reusable
This commit is contained in:
+3
-3
@@ -36,8 +36,8 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiAppManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiFwHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiMusicManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.HuaweiWatchfaceManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.audio.AudioInfo;
|
||||
|
||||
public class HuaweiInstallHandler implements InstallHandler {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HuaweiInstallHandler.class);
|
||||
@@ -66,7 +66,7 @@ public class HuaweiInstallHandler implements InstallHandler {
|
||||
}
|
||||
|
||||
//TODO: add proper checks
|
||||
private boolean checkMediaCompatibility(HuaweiMusicUtils.MusicCapabilities capabilities, HuaweiMusicManager.AudioInfo currentMusicInfo) {
|
||||
private boolean checkMediaCompatibility(HuaweiMusicUtils.MusicCapabilities capabilities, AudioInfo currentMusicInfo) {
|
||||
if (capabilities == null) {
|
||||
LOG.error("No media info from device");
|
||||
return false;
|
||||
@@ -257,7 +257,7 @@ public class HuaweiInstallHandler implements InstallHandler {
|
||||
if (capabilities == null) {
|
||||
capabilities = huaweiCoordinatorSupplier.getHuaweiCoordinator().getMusicInfoParams();
|
||||
}
|
||||
HuaweiMusicManager.AudioInfo currentMusicInfo = helper.getMusicInfo();
|
||||
AudioInfo currentMusicInfo = helper.getMusicInfo();
|
||||
|
||||
boolean isMediaCompatible = checkMediaCompatibility(capabilities, currentMusicInfo);
|
||||
|
||||
|
||||
+9
-99
@@ -17,17 +17,10 @@
|
||||
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huawei;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.media.MediaExtractor;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.media.MediaFormat;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -47,6 +40,8 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBZipFile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.ZipFileException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.audio.AudioInfo;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.audio.MusicUtils;
|
||||
|
||||
public class HuaweiFwHelper {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HuaweiFwHelper.class);
|
||||
@@ -62,7 +57,7 @@ public class HuaweiFwHelper {
|
||||
Bitmap previewBitmap;
|
||||
HuaweiWatchfaceManager.WatchfaceDescription watchfaceDescription;
|
||||
HuaweiAppManager.AppConfig appConfig;
|
||||
HuaweiMusicManager.AudioInfo musicInfo;
|
||||
AudioInfo musicInfo;
|
||||
Context mContext;
|
||||
|
||||
public boolean isFirmware = false;
|
||||
@@ -70,16 +65,8 @@ public class HuaweiFwHelper {
|
||||
|
||||
|
||||
public HuaweiFwHelper(final Uri uri, final Context context) {
|
||||
|
||||
this.uri = uri;
|
||||
final UriHelper uriHelper;
|
||||
this.mContext = context;
|
||||
try {
|
||||
uriHelper = UriHelper.get(uri, context);
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Failed to get uri helper for {}", uri, e);
|
||||
return;
|
||||
}
|
||||
|
||||
parseFile();
|
||||
}
|
||||
@@ -90,9 +77,11 @@ public class HuaweiFwHelper {
|
||||
} else if (parseAsMusic()) {
|
||||
fileType = FileUpload.Filetype.music;
|
||||
} else if (parseAsApp()) {
|
||||
assert appConfig != null;
|
||||
assert appConfig.bundleName != null;
|
||||
fileType = FileUpload.Filetype.app;
|
||||
} else if (parseAsWatchFace()) {
|
||||
assert watchfaceDescription != null;
|
||||
assert watchfaceDescription.screen != null;
|
||||
assert watchfaceDescription.title != null;
|
||||
fileType = FileUpload.Filetype.watchface;
|
||||
@@ -158,76 +147,6 @@ public class HuaweiFwHelper {
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getNameWithoutExtension(String fileName) {
|
||||
return fileName.indexOf(".") > 0 ? fileName.substring(0, fileName.lastIndexOf(".")) : fileName;
|
||||
}
|
||||
|
||||
private String getExtension(String fileName) {
|
||||
if (TextUtils.isEmpty(fileName)) {
|
||||
return null;
|
||||
}
|
||||
int lastIndexOf = fileName.lastIndexOf(".");
|
||||
if (lastIndexOf >= 0 && lastIndexOf + 1 < fileName.length()) {
|
||||
return fileName.substring(lastIndexOf + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private HuaweiMusicManager.AudioInfo getAudioInfo(Uri selectedUri) throws IOException {
|
||||
ContentResolver contentResolver = mContext.getContentResolver();
|
||||
String[] filePathColumn = {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
|
||||
|
||||
Cursor cursor = contentResolver.query(selectedUri, filePathColumn, null, null, null);
|
||||
if (cursor == null)
|
||||
return null;
|
||||
cursor.moveToFirst();
|
||||
|
||||
int fileNameIndex = cursor.getColumnIndex(filePathColumn[0]);
|
||||
String fileName = cursor.getString(fileNameIndex);
|
||||
int fileSizeIndex = cursor.getColumnIndex(filePathColumn[1]);
|
||||
long fileSize = cursor.getLong(fileSizeIndex);
|
||||
cursor.close();
|
||||
|
||||
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
mmr.setDataSource(mContext, selectedUri);
|
||||
|
||||
String title = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
|
||||
String artist = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
|
||||
|
||||
if (TextUtils.isEmpty(title)) {
|
||||
title = getNameWithoutExtension(fileName);
|
||||
}
|
||||
if (TextUtils.isEmpty(artist)) {
|
||||
artist = "Unknown";
|
||||
}
|
||||
|
||||
MediaExtractor mex = new MediaExtractor();
|
||||
mex.setDataSource(mContext, selectedUri, null);
|
||||
|
||||
|
||||
MediaFormat mf = mex.getTrackFormat(0);
|
||||
|
||||
int bitrate = -1; // TODO: calculate or get bitrate
|
||||
int sampleRate = mf.getInteger(MediaFormat.KEY_SAMPLE_RATE);
|
||||
int channels = mf.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
|
||||
long duration = mf.getLong(MediaFormat.KEY_DURATION);
|
||||
|
||||
LOG.info("bitRate: {}", bitrate);
|
||||
LOG.info("sampleRate: {}", sampleRate);
|
||||
LOG.info("channelCount: {}", channels);
|
||||
LOG.info("duration: {}", duration);
|
||||
|
||||
String extension = getExtension(fileName);
|
||||
if (!TextUtils.isEmpty(extension)) {
|
||||
extension = extension.toLowerCase();
|
||||
}
|
||||
|
||||
HuaweiMusicManager.AudioInfo audioInfo = new HuaweiMusicManager.AudioInfo(fileName, fileSize, title, artist, extension);
|
||||
audioInfo.setCharacteristics(duration, sampleRate, bitrate, (byte) channels);
|
||||
|
||||
return audioInfo;
|
||||
}
|
||||
|
||||
private byte[] getFileData(UriHelper uriHelper) throws IOException {
|
||||
InputStream inputStream = uriHelper.openInputStream();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
@@ -245,19 +164,10 @@ public class HuaweiFwHelper {
|
||||
boolean parseAsMusic() {
|
||||
try {
|
||||
final UriHelper uriHelper = UriHelper.get(uri, this.mContext);
|
||||
|
||||
String mimeType = mContext.getContentResolver().getType(uri);
|
||||
LOG.info("File mime type: {}", mimeType);
|
||||
|
||||
if (mimeType == null || !mimeType.startsWith("audio/"))
|
||||
return false;
|
||||
|
||||
musicInfo = getAudioInfo(uri);
|
||||
musicInfo = MusicUtils.audioInfoFromUri(mContext, uri);
|
||||
if (musicInfo == null)
|
||||
return false;
|
||||
|
||||
musicInfo.setMimeType(mimeType);
|
||||
|
||||
byte[] musicData = getFileData(uriHelper);
|
||||
|
||||
fileName = musicInfo.getFileName();
|
||||
@@ -337,8 +247,8 @@ public class HuaweiFwHelper {
|
||||
byte[] bom = new byte[3];
|
||||
// get the first 3 bytes
|
||||
bb.get(bom, 0, bom.length);
|
||||
String content = new String(GB.hexdump(bom));
|
||||
String xmlDescription = null;
|
||||
String content = GB.hexdump(bom);
|
||||
String xmlDescription;
|
||||
if ("efbbbf".equalsIgnoreCase(content)) {
|
||||
byte[] contentAfterFirst3Bytes = new byte[bytesDescription.length - 3];
|
||||
bb.get(contentAfterFirst3Bytes, 0, contentAfterFirst3Bytes.length);
|
||||
@@ -405,7 +315,7 @@ public class HuaweiFwHelper {
|
||||
return appConfig;
|
||||
}
|
||||
|
||||
public HuaweiMusicManager.AudioInfo getMusicInfo() {
|
||||
public AudioInfo getMusicInfo() {
|
||||
return musicInfo;
|
||||
}
|
||||
|
||||
|
||||
+1
-87
@@ -39,97 +39,11 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.GetM
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendMusicOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huawei.requests.SendUploadMusicFileInfoResponse;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.audio.AudioInfo;
|
||||
|
||||
public class HuaweiMusicManager {
|
||||
static Logger LOG = LoggerFactory.getLogger(HuaweiMusicManager.class);
|
||||
|
||||
public static class AudioInfo {
|
||||
private final String fileName;
|
||||
private final long fileSize;
|
||||
private final String title;
|
||||
private final String artist;
|
||||
private final String extension;
|
||||
|
||||
private String mimeType;
|
||||
|
||||
private long duration;
|
||||
private int sampleRate;
|
||||
private int bitrate;
|
||||
private byte channels;
|
||||
|
||||
//public byte musicEncode = -1; // TODO: not sure
|
||||
//public short unknownBitrate = -1; // TODO: not sure
|
||||
|
||||
public AudioInfo(String fileName, long fileSize, String title, String artist, String extension) {
|
||||
this.fileName = fileName;
|
||||
this.fileSize = fileSize;
|
||||
this.title = title;
|
||||
this.artist = artist;
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public long getFileSize() { return fileSize;}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getArtist() {
|
||||
return artist;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
public void setMimeType(String mimeType) {
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
public void setCharacteristics(long duration, int sampleRate, int bitrate, byte channels) {
|
||||
this.duration = duration;
|
||||
this.sampleRate = sampleRate;
|
||||
this.bitrate = bitrate;
|
||||
this.channels = channels;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
public int getBitrate() {
|
||||
return bitrate;
|
||||
}
|
||||
|
||||
public byte getChannels() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuffer sb = new StringBuffer("AudioInfo{");
|
||||
sb.append("fileName='").append(fileName).append('\'');
|
||||
sb.append("fileSize='").append(fileSize).append('\'');
|
||||
sb.append(", title='").append(title).append('\'');
|
||||
sb.append(", artist='").append(artist).append('\'');
|
||||
sb.append(", mimeType='").append(mimeType).append('\'');
|
||||
sb.append('}');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private final HuaweiSupportProvider support;
|
||||
|
||||
private AudioInfo currentMusicInfo;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util.audio;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBToStringBuilder;
|
||||
|
||||
public class AudioInfo {
|
||||
private final String fileName;
|
||||
private final long fileSize;
|
||||
private final String title;
|
||||
private final String artist;
|
||||
private final String mimeType;
|
||||
private final String extension;
|
||||
|
||||
private long duration;
|
||||
private int sampleRate;
|
||||
private int bitrate;
|
||||
private byte channels;
|
||||
|
||||
public AudioInfo(final String fileName,
|
||||
final long fileSize,
|
||||
final String title,
|
||||
final String artist,
|
||||
final String mimeType,
|
||||
final String extension) {
|
||||
this.fileName = fileName;
|
||||
this.fileSize = fileSize;
|
||||
this.title = title;
|
||||
this.artist = artist;
|
||||
this.mimeType = mimeType;
|
||||
this.extension = extension;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getArtist() {
|
||||
return artist;
|
||||
}
|
||||
|
||||
public String getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
public void setCharacteristics(final long duration, final int sampleRate, final int bitrate, final byte channels) {
|
||||
this.duration = duration;
|
||||
this.sampleRate = sampleRate;
|
||||
this.bitrate = bitrate;
|
||||
this.channels = channels;
|
||||
}
|
||||
|
||||
public long getDuration() {
|
||||
return duration;
|
||||
}
|
||||
|
||||
public int getSampleRate() {
|
||||
return sampleRate;
|
||||
}
|
||||
|
||||
public int getBitrate() {
|
||||
return bitrate;
|
||||
}
|
||||
|
||||
public byte getChannels() {
|
||||
return channels;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
final GBToStringBuilder tsb = new GBToStringBuilder(this);
|
||||
tsb.append("fileName", fileName);
|
||||
tsb.append("fileSize", fileSize);
|
||||
tsb.append("title", title);
|
||||
tsb.append("artist", artist);
|
||||
tsb.append("mimeType", mimeType);
|
||||
return tsb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.util.audio;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.media.MediaExtractor;
|
||||
import android.media.MediaFormat;
|
||||
import android.media.MediaMetadataRetriever;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
public class MusicUtils {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MusicUtils.class);
|
||||
|
||||
@Nullable
|
||||
public static AudioInfo audioInfoFromUri(final Context context, final Uri uri) {
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
final String mimeType = context.getContentResolver().getType(uri);
|
||||
if (mimeType == null || !mimeType.startsWith("audio/")) {
|
||||
LOG.warn("Mime type is not an audio file: {}", mimeType);
|
||||
return null;
|
||||
}
|
||||
|
||||
final String[] filePathColumn = {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE};
|
||||
|
||||
final Cursor cursor = contentResolver.query(uri, filePathColumn, null, null, null);
|
||||
if (cursor == null)
|
||||
return null;
|
||||
cursor.moveToFirst();
|
||||
|
||||
final int fileNameIndex = cursor.getColumnIndex(filePathColumn[0]);
|
||||
final String fileName = cursor.getString(fileNameIndex);
|
||||
final int fileSizeIndex = cursor.getColumnIndex(filePathColumn[1]);
|
||||
final long fileSize = cursor.getLong(fileSizeIndex);
|
||||
cursor.close();
|
||||
|
||||
final MediaMetadataRetriever mmr = new MediaMetadataRetriever();
|
||||
mmr.setDataSource(context, uri);
|
||||
|
||||
String title = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
|
||||
String artist = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
|
||||
|
||||
if (TextUtils.isEmpty(title)) {
|
||||
title = getNameWithoutExtension(fileName);
|
||||
}
|
||||
if (TextUtils.isEmpty(artist)) {
|
||||
artist = context.getString(R.string.unknown);
|
||||
}
|
||||
|
||||
String extension = getExtension(fileName);
|
||||
if (!TextUtils.isEmpty(extension)) {
|
||||
extension = extension.toLowerCase();
|
||||
}
|
||||
|
||||
final AudioInfo audioInfo = new AudioInfo(fileName, fileSize, title, artist, mimeType, extension);
|
||||
|
||||
try {
|
||||
final MediaExtractor mex = new MediaExtractor();
|
||||
mex.setDataSource(context, uri, null);
|
||||
|
||||
final MediaFormat mf = mex.getTrackFormat(0);
|
||||
|
||||
int bitrate = -1; // TODO: calculate or get bitrate
|
||||
int sampleRate = mf.getInteger(MediaFormat.KEY_SAMPLE_RATE);
|
||||
int channels = mf.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
|
||||
long duration = mf.getLong(MediaFormat.KEY_DURATION);
|
||||
|
||||
LOG.trace("bitRate: {}", bitrate);
|
||||
LOG.trace("sampleRate: {}", sampleRate);
|
||||
LOG.trace("channelCount: {}", channels);
|
||||
LOG.trace("duration: {}", duration);
|
||||
|
||||
audioInfo.setCharacteristics(duration, sampleRate, bitrate, (byte) channels);
|
||||
} catch (final IOException e) {
|
||||
LOG.error("Failed to set data source on media extractor", e);
|
||||
}
|
||||
|
||||
return audioInfo;
|
||||
}
|
||||
|
||||
private static String getNameWithoutExtension(final String fileName) {
|
||||
return fileName.indexOf(".") > 0 ? fileName.substring(0, fileName.lastIndexOf(".")) : fileName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String getExtension(final String fileName) {
|
||||
if (TextUtils.isEmpty(fileName)) {
|
||||
return null;
|
||||
}
|
||||
final int lastIndexOf = fileName.lastIndexOf(".");
|
||||
if (lastIndexOf >= 0 && lastIndexOf + 1 < fileName.length()) {
|
||||
return fileName.substring(lastIndexOf + 1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user