From: tobiasKaminsky Date: Sun, 1 Nov 2015 08:07:58 +0000 (+0100) Subject: Merge remote-tracking branch 'remotes/upstream/streaming' into beta X-Git-Tag: beta-20151122~55 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/465ff1b7b8b04132f58fdea80cdf12ce9a2e01fd?hp=24781619982f43b8f33d4fb11f073e9cb097e6b9 Merge remote-tracking branch 'remotes/upstream/streaming' into beta --- diff --git a/res/menu/file_actions_menu.xml b/res/menu/file_actions_menu.xml index 0a49e020..9b742d12 100644 --- a/res/menu/file_actions_menu.xml +++ b/res/menu/file_actions_menu.xml @@ -25,6 +25,11 @@ android:icon="@android:drawable/ic_menu_share" android:orderInCategory="1" /> + Exit Send Log Error Log + Stream file with external player + Do you want to stream this file with an external app?\n\nCAUTION: This may expose your password! diff --git a/src/com/owncloud/android/files/FileMenuFilter.java b/src/com/owncloud/android/files/FileMenuFilter.java index 065ab898..bfc3ad71 100644 --- a/src/com/owncloud/android/files/FileMenuFilter.java +++ b/src/com/owncloud/android/files/FileMenuFilter.java @@ -226,6 +226,14 @@ public class FileMenuFilter { } else { toShow.add(R.id.action_unfavorite_file); } + + // STREAM + if (mFile != null && (mFile.isAudio() || mFile.isVideo())){ + toShow.add(R.id.action_stream_file); + } else { + toHide.add(R.id.action_stream_file); + } + } } diff --git a/src/com/owncloud/android/media/MediaService.java b/src/com/owncloud/android/media/MediaService.java index e53c635f..7bd9c0c6 100644 --- a/src/com/owncloud/android/media/MediaService.java +++ b/src/com/owncloud/android/media/MediaService.java @@ -21,27 +21,32 @@ 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.support.v7.app.AlertDialog; import android.widget.Toast; import java.io.IOException; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; +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; @@ -210,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; + } + /** @@ -430,12 +454,7 @@ 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; - - } else if (mAccount == null) { + if (mAccount == null) { Toast.makeText(this, R.string.media_err_not_in_owncloud, Toast.LENGTH_LONG).show(); processStopRequest(true); return; @@ -444,12 +463,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 + 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); @@ -486,6 +505,8 @@ public class MediaService extends Service implements OnCompletionListener, OnPre 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(); } } diff --git a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java index 9a2ad917..380396a9 100644 --- a/src/com/owncloud/android/ui/fragment/OCFileListFragment.java +++ b/src/com/owncloud/android/ui/fragment/OCFileListFragment.java @@ -22,14 +22,20 @@ */ package com.owncloud.android.ui.fragment; +import android.accounts.Account; import android.app.Activity; +import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; +import android.net.Uri; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.widget.SwipeRefreshLayout; import android.view.ActionMode; +import android.support.v7.app.AlertDialog; +import android.view.ContextMenu; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -49,6 +55,7 @@ import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.files.FileMenuFilter; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.lib.resources.status.OwnCloudVersion; +import com.owncloud.android.media.MediaService; import com.owncloud.android.ui.activity.FileActivity; import com.owncloud.android.ui.activity.FileDisplayActivity; import com.owncloud.android.ui.activity.FolderPickerActivity; @@ -68,6 +75,7 @@ import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.ExceptionHandler; import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.ui.preview.PreviewTextFragment; +import com.owncloud.android.utils.FileStorageUtils; import java.io.File; import java.util.ArrayList; @@ -486,13 +494,11 @@ public class OCFileListFragment extends ExtendedListFragment { ((FileDisplayActivity)mContainerActivity).startImagePreview(file); } else if (PreviewTextFragment.canBePreviewed(file)){ ((FileDisplayActivity)mContainerActivity).startTextPreview(file); - } else if (file.isDown()) { - if (PreviewMediaFragment.canBePreviewed(file)) { + } else if (PreviewMediaFragment.canBePreviewed(file)) { // media preview ((FileDisplayActivity) mContainerActivity).startMediaPreview(file, 0, true); - } else { + } else if (file.isDown()) { mContainerActivity.getFileOperationsHelper().openFile(file); - } } else { // automatic download, preview on finish ((FileDisplayActivity) mContainerActivity).startDownloadForPreview(file); @@ -501,7 +507,6 @@ public class OCFileListFragment extends ExtendedListFragment { } else { Log_OC.d(TAG, "Null object in ListAdapter!!"); } - } /** @@ -592,10 +597,16 @@ public class OCFileListFragment extends ExtendedListFragment { if (!mTargetFile.isDown()) { // Download the file Log_OC.d(TAG, mTargetFile.getRemotePath() + " : File must be downloaded"); ((FileDisplayActivity) mContainerActivity).startDownloadForSending(mTargetFile); - + return true; } else { mContainerActivity.getFileOperationsHelper().sendDownloadedFile(mTargetFile); } + } + case R.id.action_stream_file: { + Account account = ((FileActivity)mContainerActivity).getAccount(); + Context context = MainApp.getAppContext(); + String uri = PreviewMediaFragment.generateUrlWithCredentials(account, context, mTargetFile); + MediaService.streamWithExternalApp(uri, getActivity()).show(); return true; } case R.id.action_move: { diff --git a/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java b/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java index 0dbb1a32..3f0ffc53 100644 --- a/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java +++ b/src/com/owncloud/android/ui/preview/PreviewMediaFragment.java @@ -20,10 +20,14 @@ package com.owncloud.android.ui.preview; import android.accounts.Account; +import android.accounts.AuthenticatorException; +import android.accounts.OperationCanceledException; import android.app.Activity; +import android.content.ActivityNotFoundException; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.MediaMetadataRetriever; +import android.os.AsyncTask; import android.support.v7.app.AlertDialog; import android.content.ComponentName; import android.content.Context; @@ -52,9 +56,16 @@ import android.widget.ImageView; import android.widget.Toast; import android.widget.VideoView; +import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.datamodel.ThumbnailsCacheManager; import com.owncloud.android.files.FileMenuFilter; +import com.owncloud.android.lib.common.OwnCloudAccount; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.OwnCloudClientManagerFactory; +import com.owncloud.android.lib.common.OwnCloudCredentials; +import com.owncloud.android.lib.common.accounts.AccountUtils; import com.owncloud.android.lib.common.utils.Log_OC; import com.owncloud.android.media.MediaControlView; import com.owncloud.android.media.MediaService; @@ -64,6 +75,9 @@ import com.owncloud.android.ui.dialog.ConfirmationDialogFragment; import com.owncloud.android.ui.dialog.RemoveFileDialogFragment; import com.owncloud.android.ui.fragment.FileFragment; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + /** * This fragment shows a preview of a downloaded media file (audio or video). @@ -87,6 +101,7 @@ public class PreviewMediaFragment extends FileFragment implements private ImageView mImagePreview; private VideoView mVideoPreview; private int mSavedPlaybackPosition; + private String mUri; private MediaServiceBinder mMediaServiceBinder = null; private MediaControlView mMediaController = null; @@ -184,10 +199,6 @@ public class PreviewMediaFragment extends FileFragment implements if (mAccount == null) { throw new IllegalStateException("Instanced with a NULL ownCloud Account"); } - if (!file.isDown()) { - throw new IllegalStateException("There is no local file to preview"); - } - } else { file = (OCFile) savedInstanceState.getParcelable(PreviewMediaFragment.EXTRA_FILE); @@ -198,7 +209,7 @@ public class PreviewMediaFragment extends FileFragment implements mAutoplay = savedInstanceState.getBoolean(PreviewMediaFragment.EXTRA_PLAYING); } - if (file != null && file.isDown()) { + if (file != null) { if (file.isVideo()) { mVideoPreview.setVisibility(View.VISIBLE); mImagePreview.setVisibility(View.GONE); @@ -271,7 +282,7 @@ public class PreviewMediaFragment extends FileFragment implements Log_OC.e(TAG, "onStart"); OCFile file = getFile(); - if (file != null && file.isDown()) { + if (file != null) { if (file.isAudio()) { bindMediaService(); @@ -431,8 +442,65 @@ public class PreviewMediaFragment extends FileFragment implements // load the video file in the video player ; // when done, VideoHelper#onPrepared() will be called - Uri uri = Uri.parse(getFile().getStoragePath()); - mVideoPreview.setVideoPath(uri.encode(getFile().getStoragePath())); + if (getFile().isDown()) { + mUri = getFile().getStoragePath(); + } else { + Context context = MainApp.getAppContext(); + Account account = mContainerActivity.getStorageManager().getAccount(); + + mUri = generateUrlWithCredentials(account, context, getFile()); + } + + mVideoPreview.setVideoPath(mUri); + } + + public static String generateUrlWithCredentials(Account account, Context context, OCFile file){ + OwnCloudAccount ocAccount = null; + try { + ocAccount = new OwnCloudAccount(account, context); + + final ClientGenerationTask task = new ClientGenerationTask(); + task.execute(ocAccount); + + OwnCloudClient mClient = task.get(); + String url = AccountUtils.constructFullURLForAccount(context, account) + Uri.encode(file.getRemotePath(), "/"); + OwnCloudCredentials credentials = mClient.getCredentials(); + + return url.replace("//", "//" + credentials.getUsername() + ":" + credentials.getAuthToken() + "@"); + + } catch (AccountUtils.AccountNotFoundException e) { + e.printStackTrace(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + return ""; + } + + public static class ClientGenerationTask extends AsyncTask { + @Override + protected OwnCloudClient doInBackground(Object... params) { + Object account = params[0]; + if (account instanceof OwnCloudAccount){ + try { + OwnCloudAccount ocAccount = (OwnCloudAccount) account; + return OwnCloudClientManagerFactory.getDefaultSingleton(). + getClientFor(ocAccount, MainApp.getAppContext()); + } catch (AccountUtils.AccountNotFoundException e) { + e.printStackTrace(); + } catch (OperationCanceledException e) { + e.printStackTrace(); + } catch (AuthenticatorException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + return null; + } } @@ -500,27 +568,11 @@ public class PreviewMediaFragment extends FileFragment implements */ @Override public boolean onError(MediaPlayer mp, int what, int extra) { - if (mVideoPreview.getWindowToken() != null) { - String message = MediaService.getMessageForMediaError( - getActivity(), what, extra); - new AlertDialog.Builder(getActivity()) - .setMessage(message) - .setPositiveButton(android.R.string.VideoView_error_button, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int whichButton) { - dialog.dismiss(); - VideoHelper.this.onCompletion(null); - } - }) - .setCancelable(false) - .show(); - } + MediaService.streamWithExternalApp(mUri, getActivity()).show(); return true; } - } - @Override public void onPause() { Log_OC.e(TAG, "onPause"); diff --git a/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java b/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java index 42b7fb28..383b0828 100644 --- a/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java +++ b/src/com/owncloud/android/ui/preview/PreviewVideoActivity.java @@ -207,14 +207,9 @@ public class PreviewVideoActivity extends FileActivity implements OnCompletionLi mVideoPlayer.setVideoPath(file.getStoragePath()); } else { - // not working yet String url; - try { - url = AccountUtils.constructFullURLForAccount(this, getAccount()) + file.getRemotePath(); - mVideoPlayer.setVideoURI(Uri.parse(url)); - } catch (AccountNotFoundException e) { - onError(null, MediaService.OC_MEDIA_ERROR, R.string.media_err_no_account); - } + url = PreviewMediaFragment.generateUrlWithCredentials(getAccount(), getApplicationContext(), getFile()); + mVideoPlayer.setVideoURI(Uri.parse(url)); } // create and prepare control panel for the user