Copy link to clipboard
Copied
For our game, we want one of the sounds in the game to be the notification sound when we display a local, or push notification, on Android.
Currently we have a solution we're not really happy that's below, because it requires extra Android permissions that we really feel is unnecessary. Basically you pass down the asset path, say "audio/core/reward.mp3", which is in the root "assets" folder, and then on the Android side, it pulls that file out into an InputStream, writes that to a file on the external storage, and Android's MediaPlayer plays it from there.
Obviously this mustn't be what AIR is doing whenever you play a file on Android, because you don't need "WRITE_EXTERNAL_STORAGE" to play a sound, so for our circumstance, when the app's not currently actively running, but a Push Notification comes in, how would I be able to play this file, which is packaged and used on the AS3 side of things?
The recommended way of doing this is,
MediaPlayer m = new MediaPlayer();
AssetFileDescriptor afd = context.getAssets().openFd(soundPath);
m.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
m.prepare();
m.setVolume(1f, 1f);
m.start();
playSound = false;
But that doesn't work with an error of
java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
So I need to do the unpreferred method,
public static void HandleMessage(Context context, CharSequence title, CharSequence message, String soundPath)
{
log("HandleMessage (message: '" + message + "', title: '" + title +"', icon: " + Extension.getIcon(context) + ", class: " + Extension.getEntryClass(context));
long when = System.currentTimeMillis();
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, Extension.getEntryClass(context));
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
Notification notification = builder
.setContentText(message)
.setContentIntent(contentIntent)
.setTicker(message)
.setSmallIcon(Extension.getIcon(context))
.setWhen(when)
.setAutoCancel(true)
.setVibrate(new long[] { 1000, 400 })
.build();
Boolean playSound = true;
if(null != soundPath && "" != soundPath)
{
try {
MediaPlayer m = new MediaPlayer();
String newPath = checkWriteFile(context, soundPath);
log(newPath);
if(null != newPath)
{
m.setDataSource(newPath);
m.prepare();
m.setVolume(1f, 1f);
m.start();
playSound = false;
}
} catch (IOException e) {
log(e.getLocalizedMessage());
e.printStackTrace();
}
}
if(playSound)
{
notification.sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
}
nm.notify(NotifId, notification);
NotifId++;
}
public static String checkWriteFile(Context context, String relPath)
{
Boolean exists = false;
String newPath = null;
String fullPath = Environment.getExternalStorageDirectory().getPath() + "/" + context.getPackageName() + "/temp/" + relPath;
int index = fullPath.lastIndexOf("/") + 1;
String file = fullPath.substring(index);
String path = fullPath.substring(0, index);
log(relPath + ", " + fullPath + ", " + (new File(fullPath)).exists());
if (!(new File(fullPath)).exists()) {
try {
byte[] buffer = null;
InputStream fIn = context.getAssets().open(relPath);
log("InputStream: " + fIn);
int size=0;
try {
size = fIn.available();
buffer = new byte[size];
fIn.read(buffer);
fIn.close();
} catch (IOException e) {
e.printStackTrace();
}
exists = (new File(path)).exists();
if (!exists) {
new File(path).mkdirs();
}
FileOutputStream save;
try {
save = new FileOutputStream(path + file);
save.write(buffer);
save.flush();
save.close();
newPath = fullPath;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
catch (Exception e) {
}
}
else {
newPath = fullPath;
}
return newPath;
}
Message was edited by: seaders6m Add the not working AssetFileDescriptor method
Copy link to clipboard
Copied
Feeling fairly dumb, you can just change to write to cache, or internal storage instead, changing the call to external to cache like,
String fullPath = context.getCacheDir() + "/" + context.getPackageName() + "/temp/" + relPath;
sorts it all out.
Copy link to clipboard
Copied
Hi,
I think the problem here is actually something to do with the way AIR is packaging the assets. I've been investigating the issue trying to get access to video files packaged in an AIR app from an ANE but they are sometimes compressed in the APK rather than just being stored. Once they are compressed you get the error you've encountered:
java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
I think this has to be an error in the AIR packaging, as they shouldn't be compressed. Any files like mp3, mp4, png etc shouldn't be compressed according to the Android packager.