Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,8 @@ dependencies {
// androidJacocoAnt "org.jacoco:org.jacoco.core:${jacocoVersion}"
// androidJacocoAnt "org.jacoco:org.jacoco.report:${jacocoVersion}"
// androidJacocoAnt "org.jacoco:org.jacoco.agent:${jacocoVersion}"

implementation "com.github.stateless4j:stateless4j:2.6.0"
}

configurations.all {
Expand Down
2 changes: 1 addition & 1 deletion scripts/analysis/findbugs-results.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
429
427
2 changes: 1 addition & 1 deletion src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@
<service android:name=".services.OperationsService" />
<service android:name=".files.services.FileDownloader" />
<service android:name=".files.services.FileUploader" />
<service android:name=".media.MediaService" />
<service android:name="com.nextcloud.client.media.PlayerService"/>

<activity
android:name=".ui.activity.PassCodeActivity"
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/nextcloud/client/di/AppModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@

import android.accounts.AccountManager;
import android.app.Application;
import android.app.NotificationManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.res.Resources;
import android.os.Handler;
import android.media.AudioManager;

import com.nextcloud.client.account.CurrentAccountProvider;
import com.nextcloud.client.account.UserAccountManager;
Expand Down Expand Up @@ -146,4 +148,14 @@ AsyncRunner asyncRunner() {
Handler uiHandler = new Handler();
return new ThreadPoolAsyncRunner(uiHandler, 4);
}

@Provides
NotificationManager notificationManager(Context context) {
return (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
}

@Provides
AudioManager audioManager(Context context) {
return (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
}
}
4 changes: 2 additions & 2 deletions src/main/java/com/nextcloud/client/di/ComponentsModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@

package com.nextcloud.client.di;

import com.nextcloud.client.errorhandling.ShowErrorActivity;
import com.nextcloud.client.etm.EtmActivity;
import com.nextcloud.client.logger.ui.LogsActivity;
import com.nextcloud.client.media.PlayerService;
import com.nextcloud.client.onboarding.FirstRunActivity;
import com.nextcloud.client.onboarding.WhatsNewActivity;
import com.owncloud.android.authentication.AuthenticatorActivity;
Expand Down Expand Up @@ -96,7 +96,6 @@ abstract class ComponentsModule {
@ContributesAndroidInjector abstract CopyToClipboardActivity copyToClipboardActivity();
@ContributesAndroidInjector abstract DeepLinkLoginActivity deepLinkLoginActivity();
@ContributesAndroidInjector abstract DrawerActivity drawerActivity();
@ContributesAndroidInjector abstract ShowErrorActivity errorShowActivity();
@ContributesAndroidInjector abstract ErrorsWhileCopyingHandlerActivity errorsWhileCopyingHandlerActivity();
@ContributesAndroidInjector abstract ExternalSiteWebView externalSiteWebView();
@ContributesAndroidInjector abstract FileDisplayActivity fileDisplayActivity();
Expand Down Expand Up @@ -156,4 +155,5 @@ abstract class ComponentsModule {

@ContributesAndroidInjector abstract AccountManagerService accountManagerService();
@ContributesAndroidInjector abstract OperationsService operationsService();
@ContributesAndroidInjector abstract PlayerService playerService();
}
45 changes: 45 additions & 0 deletions src/main/java/com/nextcloud/client/media/AudioFocus.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* Nextcloud Android client application
*
* @author Chris Narkiewicz
*
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.media

import android.media.AudioManager

/**
* Simplified audio focus values, relevant to application's media player experience.
*/
internal enum class AudioFocus {

LOST,
DUCK,
FOCUS;

companion object {
fun fromPlatformFocus(audioFocus: Int): AudioFocus? = when (audioFocus) {
AudioManager.AUDIOFOCUS_GAIN -> FOCUS
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT -> FOCUS
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -> FOCUS
AudioManager.AUDIOFOCUS_LOSS -> LOST
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> LOST
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> DUCK
else -> null
}
}
}
95 changes: 95 additions & 0 deletions src/main/java/com/nextcloud/client/media/AudioFocusManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/**
* Nextcloud Android client application
*
* @author Chris Narkiewicz
*
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.media

import android.media.AudioFocusRequest
import android.media.AudioManager
import android.os.Build

/**
* Wrapper around audio manager exposing simplified audio focus API and
* hiding platform API level differences.
*
* @param audioManger Platform audio manager
* @param onFocusChange Called when audio focus changes, including acquired and released focus states
*/
internal class AudioFocusManager(
private val audioManger: AudioManager,
private val onFocusChange: (AudioFocus) -> Unit
) {

private val focusListener = object : AudioManager.OnAudioFocusChangeListener {
override fun onAudioFocusChange(focusChange: Int) {
val focus = when (focusChange) {
AudioManager.AUDIOFOCUS_GAIN -> AudioFocus.FOCUS
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT -> AudioFocus.FOCUS
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK -> AudioFocus.FOCUS
AudioManager.AUDIOFOCUS_LOSS -> AudioFocus.LOST
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> AudioFocus.LOST
AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK -> AudioFocus.DUCK
else -> null
}
focus?.let { onFocusChange(it) }
}
}
private var focusRequest: AudioFocusRequest? = null

init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
focusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN).run {
setWillPauseWhenDucked(true)
setOnAudioFocusChangeListener(focusListener)
}.build()
}
}

/**
* Request audio focus. Focus is reported via callback.
* If focus cannot be gained, lost of focus is reported.
*/
fun requestFocus() {
val requestResult = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
focusRequest?.let { audioManger.requestAudioFocus(it) }
} else {
audioManger.requestAudioFocus(focusListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN)
}

if (requestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
focusListener.onAudioFocusChange(AudioManager.AUDIOFOCUS_GAIN)
} else {
focusListener.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS)
}
}

/**
* Release audio focus. Loss of focus is reported via callback.
*/
fun releaseFocus() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
focusRequest?.let {
audioManger.abandonAudioFocusRequest(it)
} ?: AudioManager.AUDIOFOCUS_REQUEST_FAILED
} else {
audioManger.abandonAudioFocus(focusListener)
}
focusListener.onAudioFocusChange(AudioManager.AUDIOFOCUS_LOSS)
}
}
94 changes: 94 additions & 0 deletions src/main/java/com/nextcloud/client/media/ErrorFormat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Nextcloud Android client application
*
* @author David A. Velasco
* @author masensio
* @author Chris Narkiewicz
* Copyright (C) 2013 David A. Velasco
* Copyright (C) 2016 masensio
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.media

import android.content.Context
import android.media.MediaPlayer
import com.owncloud.android.R

/**
* This code has been moved from legacy media player service.
*/
@Deprecated("This legacy helper should be refactored")
@Suppress("ComplexMethod") // it's legacy code
object ErrorFormat {

/** Error code for specific messages - see regular error codes at [MediaPlayer] */
const val OC_MEDIA_ERROR = 0

@JvmStatic
fun toString(context: Context?, what: Int, extra: Int): String {
val messageId: Int

if (what == OC_MEDIA_ERROR) {
messageId = extra
} else if (extra == MediaPlayer.MEDIA_ERROR_UNSUPPORTED) {
/* Added in API level 17
Bitstream is conforming to the related coding standard or file spec,
but the media framework does not support the feature.
Constant Value: -1010 (0xfffffc0e)
*/
messageId = R.string.media_err_unsupported
} else if (extra == MediaPlayer.MEDIA_ERROR_IO) {
/* Added in API level 17
File or network related operation errors.
Constant Value: -1004 (0xfffffc14)
*/
messageId = R.string.media_err_io
} else if (extra == MediaPlayer.MEDIA_ERROR_MALFORMED) {
/* Added in API level 17
Bitstream is not conforming to the related coding standard or file spec.
Constant Value: -1007 (0xfffffc11)
*/
messageId = R.string.media_err_malformed
} else if (extra == MediaPlayer.MEDIA_ERROR_TIMED_OUT) {
/* Added in API level 17
Some operation takes too long to complete, usually more than 3-5 seconds.
Constant Value: -110 (0xffffff92)
*/
messageId = R.string.media_err_timeout
} else if (what == MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK) {
/* Added in API level 3
The video is streamed and its container is not valid for progressive playback i.e the video's index
(e.g moov atom) is not at the start of the file.
Constant Value: 200 (0x000000c8)
*/
messageId = R.string.media_err_invalid_progressive_playback
} else {
/* MediaPlayer.MEDIA_ERROR_UNKNOWN
Added in API level 1
Unspecified media player error.
Constant Value: 1 (0x00000001)
*/
/* MediaPlayer.MEDIA_ERROR_SERVER_DIED)
Added in API level 1
Media server died. In this case, the application must release the MediaPlayer
object and instantiate a new one.
Constant Value: 100 (0x00000064)
*/
messageId = R.string.media_err_unknown
}
return context?.getString(messageId) ?: "Media error"
}
}
49 changes: 49 additions & 0 deletions src/main/java/com/nextcloud/client/media/LoadUrlTask.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Nextcloud Android client application
*
* @author Chris Narkiewicz
* @author Tobias Kaminsky
*
* Copyright (C) 2019 Chris Narkiewicz <hello@ezaquarii.com>
* Copyright (C) 2018 Tobias Kaminsky
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.client.media

import android.os.AsyncTask
import com.owncloud.android.files.StreamMediaFileOperation
import com.owncloud.android.lib.common.OwnCloudClient

internal class LoadUrlTask(
private val client: OwnCloudClient,
private val fileId: String,
private val onResult: (String?) -> Unit
) : AsyncTask<Void, Void, String>() {

override fun doInBackground(vararg args: Void): String? {
val operation = StreamMediaFileOperation(fileId)
val result = operation.execute(client)
return when (result.isSuccess) {
true -> result.data[0] as String
false -> null
}
}

override fun onPostExecute(url: String?) {
if (!isCancelled) {
onResult(url)
}
}
}
Loading