gt:             mAudioWife = new AudioWife();
context: package org.awesomeapp.messenger.ui.widgets;
  
  /***
   * The MIT License (MIT)
  
   * Copyright (c) 2014 Jaydeep
  
   * Permission is hereby granted, free of charge, to any person obtaining a copy
   * of this software and associated documentation files (the "Software"), to deal
   * in the Software without restriction, including without limitation the rights
   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the Software is
   * furnished to do so, subject to the following conditions:
  
   * The above copyright notice and this permission notice shall be included in all
   * copies or substantial portions of the Software.
  
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   * SOFTWARE.
   */
  
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.concurrent.TimeUnit;
  
  import android.app.Activity;
  import android.content.Context;
  import android.media.AudioManager;
  import android.media.MediaDataSource;
  import android.media.MediaPlayer;
  import android.media.MediaPlayer.OnCompletionListener;
  import android.net.Uri;
  import android.os.Build;
  import android.os.Handler;
  import android.util.Log;
  import android.view.LayoutInflater;
  import android.view.View;
  import android.view.ViewGroup;
  import android.widget.Button;
  import android.widget.ImageView;
  import android.widget.SeekBar;
  import android.widget.TextView;
  
  import org.awesomeapp.messenger.util.HttpMediaStreamer;
  
  import im.zom.messenger.R;
  import info.guardianproject.iocipher.File;
  
  /***
   * A simple audio player wrapper for Android
   ***/
  public class AudioWife {
  
      private static final String TAG = AudioWife.class.getSimpleName();
  
      /***
       * Keep a single copy of this in memory unless required to create a new instance explicitly.
       ****/
      private static AudioWife mAudioWife;
  
      /****
       * Playback progress update time in milliseconds
       ****/
      private static final int AUDIO_PROGRESS_UPDATE_TIME = 100;
  
      // TODO: externalize the error messages.
      private static final String ERROR_PLAYVIEW_NULL = "Play view cannot be null";
      private static final String ERROR_PLAYTIME_CURRENT_NEGATIVE = "Current playback time cannot be negative";
      private static final String ERROR_PLAYTIME_TOTAL_NEGATIVE = "Total playback time cannot be negative";
  
      private Handler mProgressUpdateHandler;
  
      private MediaPlayer mMediaPlayer;
  
      private SeekBar mSeekBar;
  
      @Deprecated
      /***
       * Set both current playack time and total runtime
       * of the audio in the UI.
       */
      private TextView mPlaybackTime;
  
      private View mPlayButton;
      private View mPauseButton;
  
      /***
       * Indicates the current run-time of the audio being played
       */
      private TextView mRunTime;
  
      /***
       * Indicates the total duration of the audio being played.
       */
      private TextView mTotalTime;
  
      /***
       * Set if AudioWife is using the default UI provided with the library.
       * **/
      private boolean mHasDefaultUi;
  
      /****
       * Array to hold custom completion listeners
       ****/
      private ArrayList<OnCompletionListener> mCompletionListeners = new ArrayList<OnCompletionListener>();
  
      private ArrayList<View.OnClickListener> mPlayListeners = new ArrayList<View.OnClickListener>();
  
      private ArrayList<View.OnClickListener> mPauseListeners = new ArrayList<View.OnClickListener>();
  
      /***
       * Audio URI
       ****/
      private static Uri mUri;
  
      public static AudioWife getInstance() {
  
          if (mAudioWife == null) {
              mAudioWife = new AudioWife();
          }
  
          return mAudioWife;
      }
  
      private Runnable mUpdateProgress = new Runnable() {
  
          public void run() {
  
              if (mSeekBar == null) {
                  return;
              }
  
              if (mProgressUpdateHandler != null && mMediaPlayer.isPlaying()) {
                  mSeekBar.setProgress((int) mMediaPlayer.getCurrentPosition());
                  int currentTime = mMediaPlayer.getCurrentPosition();
                  updatePlaytime(currentTime);
                  updateRuntime(currentTime);
                  // repeat the process
                  mProgressUpdateHandler.postDelayed(this, AUDIO_PROGRESS_UPDATE_TIME);
              } else {
                  // DO NOT update UI if the player is paused
              }
          }
      };
  
      /***
       * Starts playing audio file associated. Before playing the audio, visibility of appropriate UI
       * controls is made visible. Calling this method has no effect if the audio is already being
       * played.
       ****/
      public void play() {
  
          // if play button itself is null, the whole purpose of AudioWife is
          // defeated.
          if (mPlayButton == null) {
              throw new IllegalStateException(ERROR_PLAYVIEW_NULL);
          }
  
          if (mUri == null) {
              throw new IllegalStateException("Uri cannot be null. Call init() before calling this method");
          }
  
          if (mMediaPlayer == null) {
              //throw new IllegalStateException("Call init() before calling this method");
              return;
          }
  
          if (mMediaPlayer.isPlaying()) {
              return;
          }
  
          mProgressUpdateHandler.postDelayed(mUpdateProgress, AUDIO_PROGRESS_UPDATE_TIME);
  
          // enable visibility of all UI controls.
          setViewsVisibility();
  
          mMediaPlayer.start();
  
          setPausable();
      }
  
      /**
       * Ensure the views are visible before playing the audio.
       */
      private void setViewsVisibility() {
  
          if (mSeekBar != null) {
              mSeekBar.setVisibility(View.VISIBLE);
          }
  
          if (mPlaybackTime != null) {
              mPlaybackTime.setVisibility(View.VISIBLE);
          }
  
          if (mRunTime != null) {
              mRunTime.setVisibility(View.VISIBLE);
          }
  
          if (mTotalTime != null) {
              mTotalTime.setVisibility(View.VISIBLE);
          }
  
          if (mPlayButton != null) {
              mPlayButton.setVisibility(View.VISIBLE);
          }
  
          if (mPauseButton != null) {
              mPauseButton.setVisibility(View.VISIBLE);
          }
      }
  
      /***
       * Pause the audio being played. Calling this method has no effect if the audio is already
       * paused
       */
      public void pause() {
  
          if (mMediaPlayer == null) {
              return;
          }
  
          if (mMediaPlayer.isPlaying()) {
              mMediaPlayer.pause();
              setPlayable();
          }
      }
  
      @Deprecated
      private void updatePlaytime(int currentTime) {
  
          if (mPlaybackTime == null) {
              return;
          }
  
          if (currentTime < 0) {
              throw new IllegalArgumentException(ERROR_PLAYTIME_CURRENT_NEGATIVE);
          }
  
          StringBuilder playbackStr = new StringBuilder();
  
          // set the current time
          // its ok to show 00:00 in the UI
          playbackStr.append(String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes((long) currentTime), TimeUnit.MILLISECONDS.toSeconds((long) currentTime) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) currentTime))));
  
          playbackStr.append("/");
  
          // show total duration.
          long totalDuration = 0;
  
          if (mMediaPlayer != null) {
              try {
                  totalDuration = mMediaPlayer.getDuration();
              } catch (IllegalStateException e) {
                  e.printStackTrace();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
  
          // set total time as the audio is being played
          if (totalDuration != 0) {
              playbackStr.append(String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes((long) totalDuration), TimeUnit.MILLISECONDS.toSeconds((long) totalDuration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) totalDuration))));
          } else {
              Log.w(TAG, "Something strage this audio track duration in zero");
          }
  
          mPlaybackTime.setText(playbackStr);
  
          // DebugLog.i(currentTime + " / " + totalDuration);
      }
  
      private void updateRuntime(int currentTime) {
  
          if (mRunTime == null) {
              // this view can be null if the user
              // does not want to use it. Don't throw
              // an exception.
              return;
          }
  
          if (currentTime < 0) {
              throw new IllegalArgumentException(ERROR_PLAYTIME_CURRENT_NEGATIVE);
          }
  
          StringBuilder playbackStr = new StringBuilder();
  
          // set the current time
          // its ok to show 00:00 in the UI
          playbackStr.append(String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes((long) currentTime), TimeUnit.MILLISECONDS.toSeconds((long) currentTime) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) currentTime))));
  
          mRunTime.setText(playbackStr);
  
          // DebugLog.i(currentTime + " / " + totalDuration);
      }
  
      private void setTotalTime() {
  
          if (mTotalTime == null) {
              // this view can be null if the user
              // does not want to use it. Don't throw
              // an exception.
              return;
          }
  
          StringBuilder playbackStr = new StringBuilder();
          long totalDuration = 0;
  
          // by this point the media player is brought to ready state
          // by the call to init().
          if (mMediaPlayer != null) {
              try {
                  totalDuration = mMediaPlayer.getDuration();
              } catch (IllegalStateException e) {
                  e.printStackTrace();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
  
          if (totalDuration < 0) {
              throw new IllegalArgumentException(ERROR_PLAYTIME_TOTAL_NEGATIVE);
          }
  
          // set total time as the audio is being played
          if (totalDuration != 0) {
              playbackStr.append(String.format("%02d:%02d", TimeUnit.MILLISECONDS.toMinutes((long) totalDuration), TimeUnit.MILLISECONDS.toSeconds((long) totalDuration) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes((long) totalDuration))));
          }
  
          mTotalTime.setText(playbackStr);
      }
  
      /***
       * Changes audiowife state to enable play functionality.
       */
      private void setPlayable() {
          if (mPlayButton != null) {
              mPlayButton.setVisibility(View.VISIBLE);
          }
  
          if (mPauseButton != null) {
              mPauseButton.setVisibility(View.GONE);
          }
      }
  
      /****
       * Changes audio wife to enable pause functionality.
       */
      private void setPausable() {
          if (mPlayButton != null) {
              mPlayButton.setVisibility(View.GONE);
          }
  
          if (mPauseButton != null) {
              mPauseButton.setVisibility(View.VISIBLE);
          }
      }
  
      /***
       * Initialize the audio player. This method should be the first one to be called before starting
       * to play audio using {@link nl.changer.audiowife.AudioWife}
       *
       * @param ctx
       *            {@link android.app.Activity} Context
       * @param uri
       *            Uri of the audio to be played.
       ****/
      public AudioWife init(Context ctx, Uri uri, String mimeType) throws IOException {
  
          if (uri == null) {
              throw new IllegalArgumentException("Uri cannot be null");
          }
  
          if (mAudioWife == null) {
  