title: Android - Play sound from assets without android.permission.WRITE_EXTERNAL_STORAGE
body: <p>For our game, written in Adobe AIR, we want one of the sounds in the game to be the notification sound when we display a local, or push notification, on Android.</p>
  
  <p>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.</p>
  
  <p>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?</p>
  
  <p>The recommended way of doing this is,</p>
  
  <pre><code>    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;
  </code></pre>
  
  <p>But that doesn't work with an error of</p>
  
  <pre><code> java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
  </code></pre>
  
  <p>So I need to do the unpreferred method,</p>
  
  <pre><code>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);
  
      Notification notification = new NotificationCompat.Builder(context)
          .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 &amp;&amp; "" != 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) {
              log(e.getLocalizedMessage());
              e.printStackTrace();
          }
      }
      else {
          newPath = fullPath;
      }
  
      return newPath;
  }
  </code></pre>