tidy up
[pub/Android/ownCloud.git] / src / com / owncloud / android / media / MediaService.java
index f8e70fe..15fad66 100644 (file)
@@ -1,10 +1,12 @@
-/* ownCloud Android client application
- *   Copyright 2013 ownCloud Inc.
+/**
+ *   ownCloud Android client application
+ *
+ *   @author David A. Velasco
+ *   Copyright (C) 2015 ownCloud Inc.
  *
  *   This program is free software: you can redistribute it and/or modify
- *   it under the terms of the GNU General Public License as published by
- *   the Free Software Foundation, either version 3 of the License, or
- *   (at your option) any later version.
+ *   it under the terms of the GNU General Public License version 2,
+ *   as published by the Free Software Foundation.
  *
  *   This program is distributed in the hope that it will be useful,
  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 package com.owncloud.android.media;
 
 import android.accounts.Account;
+import android.app.Activity;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Service;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.content.Intent;
 import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
 import android.media.MediaPlayer.OnErrorListener;
 import android.media.MediaPlayer.OnPreparedListener;
+import android.net.Uri;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiManager.WifiLock;
 import android.os.IBinder;
 import android.os.PowerManager;
-import android.util.Log;
-import android.widget.MediaController;
+import android.support.v7.app.AlertDialog;
 import android.widget.Toast;
 
 import java.io.IOException;
 
-import com.owncloud.android.AccountUtils;
 import com.owncloud.android.R;
 import com.owncloud.android.datamodel.OCFile;
-import com.owncloud.android.ui.activity.FileDetailActivity;
-import com.owncloud.android.ui.fragment.FileDetailFragment;
+import com.owncloud.android.lib.common.accounts.AccountUtils;
+import com.owncloud.android.lib.common.utils.Log_OC;
+import com.owncloud.android.ui.activity.FileActivity;
+import com.owncloud.android.ui.activity.FileDisplayActivity;
+
 
 /**
  * Service that handles media playback, both audio and video. 
  * 
  * Waits for Intents which signal the service to perform specific operations: Play, Pause,
  * Rewind, etc.
- * 
- * @author David A. Velasco
  */
 public class MediaService extends Service implements OnCompletionListener, OnPreparedListener,
                 OnErrorListener, AudioManager.OnAudioFocusChangeListener {
@@ -68,12 +72,15 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
     /// Keys to add extras to the action
     public static final String EXTRA_FILE = MY_PACKAGE + ".extra.FILE";
     public static final String EXTRA_ACCOUNT = MY_PACKAGE + ".extra.ACCOUNT";
+    public static String EXTRA_START_POSITION = MY_PACKAGE + ".extra.START_POSITION";
+    public static final String EXTRA_PLAY_ON_LOAD = MY_PACKAGE + ".extra.PLAY_ON_LOAD";
+
 
     /** Error code for specific messages - see regular error codes at {@link MediaPlayer} */
     public static final int OC_MEDIA_ERROR = 0;
 
     /** Time To keep the control panel visible when the user does not use it */
-    public static final int MEDIA_CONTROL_SHORT_LIFE = 5000;
+    public static final int MEDIA_CONTROL_SHORT_LIFE = 4000;
     
     /** Time To keep the control panel visible when the user does not use it */
     public static final int MEDIA_CONTROL_PERMANENT = 0;
@@ -129,6 +136,12 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
     /** Account holding the file being played */
     private Account mAccount;
 
+    /** Flag signaling if the audio should be played immediately when the file is prepared */ 
+    protected boolean mPlayOnPrepared;
+
+    /** Position, in miliseconds, where the audio should be started */
+    private int mStartPosition;
+    
     /** Interface to access the service through binding */
     private IBinder mBinder;
 
@@ -202,6 +215,25 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
         return context.getString(messageId);
     }
 
+    public static AlertDialog.Builder streamWithExternalApp(final String uri, final Activity activity){
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setMessage(activity.getString(R.string.stream_expose_password))
+                .setPositiveButton(activity.getString(R.string.common_yes),
+                                   new DialogInterface.OnClickListener() {
+                                        public void onClick(DialogInterface dialog, int id) {
+                                            Intent i = new Intent(Intent.ACTION_VIEW);
+                                            i.setData(Uri.parse(uri));
+                                            activity.startActivity(i);
+                                        }
+                                    })
+                .setNegativeButton(activity.getString(R.string.common_no), new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int id) {
+                        // User cancelled the dialog
+                    }
+                });
+        return builder;
+    }
+
 
     
     /**
@@ -211,7 +243,8 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
      */
     @Override
     public void onCreate() {
-        Log.d(TAG, "Creating ownCloud media service");
+        super.onCreate();
+        Log_OC.d(TAG, "Creating ownCloud media service");
 
         mWifiLock = ((WifiManager) getSystemService(Context.WIFI_SERVICE)).
                 createWifiLock(WifiManager.WIFI_MODE_FULL, MEDIA_WIFI_LOCK_TAG);
@@ -252,6 +285,8 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
         if (mState != State.PREPARING) {
             mFile = intent.getExtras().getParcelable(EXTRA_FILE);
             mAccount = intent.getExtras().getParcelable(EXTRA_ACCOUNT);
+            mPlayOnPrepared = intent.getExtras().getBoolean(EXTRA_PLAY_ON_LOAD, false);
+            mStartPosition = intent.getExtras().getInt(EXTRA_START_POSITION, 0);
             tryToGetAudioFocus();
             playMedia();
         }
@@ -282,7 +317,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
     
     /**
      * Makes sure the media player exists and has been reset. This will create the media player
-     * if needed, or reset the existing media player if one already exists.
+     * if needed. reset the existing media player if one already exists.
      */
     protected void createMediaPlayerIfNeeded() {
         if (mPlayer == null) {
@@ -419,12 +454,12 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
         releaseResources(false); // release everything except MediaPlayer
 
         try {
-            if (mFile == null) { 
-                Toast.makeText(this, R.string.media_err_nothing_to_play, Toast.LENGTH_LONG).show();
-                processStopRequest(true);
-                return;
+//            if (mFile == null) {
+//                Toast.makeText(this, R.string.media_err_nothing_to_play, Toast.LENGTH_LONG).show();
+//                processStopRequest(true);
+//                return;
                 
-            } else if (mAccount == null) {
+            if (mAccount == null) {
                 Toast.makeText(this, R.string.media_err_not_in_owncloud, Toast.LENGTH_LONG).show();
                 processStopRequest(true);
                 return;
@@ -433,12 +468,12 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
             createMediaPlayerIfNeeded();
             mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
             String url = mFile.getStoragePath();
-            /* Streaming is not possible right now
+            // Streaming is not possible right now
             if (url == null || url.length() <= 0) {
                 url = AccountUtils.constructFullURLForAccount(this, mAccount) + mFile.getRemotePath();
             }
             mIsStreaming = url.startsWith("http:") || url.startsWith("https:");
-            */
+
             mIsStreaming = false;
             
             mPlayer.setDataSource(url);
@@ -457,24 +492,26 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
             }
             
         } catch (SecurityException e) {
-            Log.e(TAG, "SecurityException playing " + mAccount.name + mFile.getRemotePath(), e);
+            Log_OC.e(TAG, "SecurityException playing " + mAccount.name + mFile.getRemotePath(), e);
             Toast.makeText(this, String.format(getString(R.string.media_err_security_ex), mFile.getFileName()), Toast.LENGTH_LONG).show();
             processStopRequest(true);
             
         } catch (IOException e) {
-            Log.e(TAG, "IOException playing " + mAccount.name + mFile.getRemotePath(), e);
+            Log_OC.e(TAG, "IOException playing " + mAccount.name + mFile.getRemotePath(), e);
             Toast.makeText(this, String.format(getString(R.string.media_err_io_ex), mFile.getFileName()), Toast.LENGTH_LONG).show();
             processStopRequest(true);
             
         } catch (IllegalStateException e) {
-            Log.e(TAG, "IllegalStateException " + mAccount.name + mFile.getRemotePath(), e);
+            Log_OC.e(TAG, "IllegalStateException " + mAccount.name + mFile.getRemotePath(), e);
             Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show();
             processStopRequest(true);
             
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "IllegalArgumentException " + mAccount.name + mFile.getRemotePath(), e);
+            Log_OC.e(TAG, "IllegalArgumentException " + mAccount.name + mFile.getRemotePath(), e);
             Toast.makeText(this, String.format(getString(R.string.media_err_unexpected), mFile.getFileName()), Toast.LENGTH_LONG).show();
             processStopRequest(true);
+        } catch (AccountUtils.AccountNotFoundException e) {
+            e.printStackTrace();
         }
     }
 
@@ -482,7 +519,15 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
     /** Called when media player is done playing current song. */
     public void onCompletion(MediaPlayer player) {
         Toast.makeText(this, String.format(getString(R.string.media_event_done, mFile.getFileName())), Toast.LENGTH_LONG).show();
-        processStopRequest(true);
+        if (mMediaController != null) {
+            // somebody is still bound to the service
+            player.seekTo(0);
+            processPauseRequest();
+            mMediaController.updatePausePlay();
+        } else {
+            // nobody is bound
+            processStopRequest(true);
+        }
         return;
     }
     
@@ -498,7 +543,12 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
         if (mMediaController != null) {
             mMediaController.setEnabled(true);
         }
+        player.seekTo(mStartPosition);
         configAndStartMediaPlayer();
+        if (!mPlayOnPrepared) {
+            processPauseRequest();
+        }
+        
         if (mMediaController != null) {
             mMediaController.updatePausePlay();
         }
@@ -511,9 +561,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
     @SuppressWarnings("deprecation")
     private void updateNotification(String content) {
         // TODO check if updating the Intent is really necessary
-        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+        Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
+        showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, mFile);
+        showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount);
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 
                                                                 (int)System.currentTimeMillis(), 
@@ -548,9 +598,9 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
 
         
         /// includes a pending intent in the notification showing the details view of the file
-        Intent showDetailsIntent = new Intent(this, FileDetailActivity.class);
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_FILE, mFile);
-        showDetailsIntent.putExtra(FileDetailFragment.EXTRA_ACCOUNT, mAccount);
+        Intent showDetailsIntent = new Intent(this, FileDisplayActivity.class);
+        showDetailsIntent.putExtra(FileActivity.EXTRA_FILE, mFile);
+        showDetailsIntent.putExtra(FileActivity.EXTRA_ACCOUNT, mAccount);
         showDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         mNotification.contentIntent = PendingIntent.getActivity(getApplicationContext(), 
                                                                 (int)System.currentTimeMillis(), 
@@ -571,7 +621,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
      * Warns the user about the error and resets the media player.
      */
     public boolean onError(MediaPlayer mp, int what, int extra) {
-        Log.e(TAG, "Error in audio playback, what = " + what + ", extra = " + extra);
+        Log_OC.e(TAG, "Error in audio playback, what = " + what + ", extra = " + extra);
         
         String message = getMessageForMediaError(this, what, extra);
         Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
@@ -615,6 +665,7 @@ public class MediaService extends Service implements OnCompletionListener, OnPre
         mState = State.STOPPED;
         releaseResources(true);
         giveUpAudioFocus();
+        super.onDestroy();
     }