diff options
Diffstat (limited to 'src')
170 files changed, 5603 insertions, 1755 deletions
diff --git a/src/com/aocate/media/AndroidMediaPlayer.java b/src/com/aocate/media/AndroidMediaPlayer.java new file mode 100644 index 000000000..17ee74a13 --- /dev/null +++ b/src/com/aocate/media/AndroidMediaPlayer.java @@ -0,0 +1,470 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.media; + +import java.io.IOException; + +import android.content.Context; +import android.media.MediaPlayer; +import android.net.Uri; +import android.util.Log; + +public class AndroidMediaPlayer extends MediaPlayerImpl { + private final static String AMP_TAG = "AocateAndroidMediaPlayer"; + + // private static final long TIMEOUT_DURATION_MS = 500; + + android.media.MediaPlayer mp = null; + + private android.media.MediaPlayer.OnBufferingUpdateListener onBufferingUpdateListener = new android.media.MediaPlayer.OnBufferingUpdateListener() { + public void onBufferingUpdate(android.media.MediaPlayer mp, int percent) { + if (owningMediaPlayer != null) { + owningMediaPlayer.lock.lock(); + try { + if ((owningMediaPlayer.onBufferingUpdateListener != null) + && (owningMediaPlayer.mpi == AndroidMediaPlayer.this)) { + owningMediaPlayer.onBufferingUpdateListener.onBufferingUpdate(owningMediaPlayer, percent); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + } + }; + + private android.media.MediaPlayer.OnCompletionListener onCompletionListener = new android.media.MediaPlayer.OnCompletionListener() { + public void onCompletion(android.media.MediaPlayer mp) { + Log.d(AMP_TAG, "onCompletionListener being called"); + if (owningMediaPlayer != null) { + owningMediaPlayer.lock.lock(); + try { + if (owningMediaPlayer.onCompletionListener != null) { + owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + } + }; + + private android.media.MediaPlayer.OnErrorListener onErrorListener = new android.media.MediaPlayer.OnErrorListener() { + public boolean onError(android.media.MediaPlayer mp, int what, int extra) { + // Once we're in errored state, any received messages are going to be junked + if (owningMediaPlayer != null) { + owningMediaPlayer.lock.lock(); + try { + if (owningMediaPlayer.onErrorListener != null) { + return owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + return false; + } + }; + + private android.media.MediaPlayer.OnInfoListener onInfoListener = new android.media.MediaPlayer.OnInfoListener() { + public boolean onInfo(android.media.MediaPlayer mp, int what, int extra) { + if (owningMediaPlayer != null) { + owningMediaPlayer.lock.lock(); + try { + if ((owningMediaPlayer.onInfoListener != null) + && (owningMediaPlayer.mpi == AndroidMediaPlayer.this)) { + return owningMediaPlayer.onInfoListener.onInfo(owningMediaPlayer, what, extra); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + return false; + } + }; + + // We have to assign this.onPreparedListener because the + // onPreparedListener in owningMediaPlayer sets the state + // to PREPARED. Due to prepareAsync, that's the only + // reasonable place to do it + // The others it just didn't make sense to have a setOnXListener that didn't use the parameter + private android.media.MediaPlayer.OnPreparedListener onPreparedListener = new android.media.MediaPlayer.OnPreparedListener() { + public void onPrepared(android.media.MediaPlayer mp) { + Log.d(AMP_TAG, "Calling onPreparedListener.onPrepared()"); + if (AndroidMediaPlayer.this.owningMediaPlayer != null) { + AndroidMediaPlayer.this.lockMuteOnPreparedCount.lock(); + try { + if (AndroidMediaPlayer.this.muteOnPreparedCount > 0) { + AndroidMediaPlayer.this.muteOnPreparedCount--; + } + else { + AndroidMediaPlayer.this.muteOnPreparedCount = 0; + if (AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener != null) { + Log.d(AMP_TAG, "Invoking AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener.onPrepared"); + AndroidMediaPlayer.this.owningMediaPlayer.onPreparedListener.onPrepared(AndroidMediaPlayer.this.owningMediaPlayer); + } + } + } + finally { + AndroidMediaPlayer.this.lockMuteOnPreparedCount.unlock(); + } + if (owningMediaPlayer.mpi != AndroidMediaPlayer.this) { + Log.d(AMP_TAG, "owningMediaPlayer has changed implementation"); + } + } + } + }; + + private android.media.MediaPlayer.OnSeekCompleteListener onSeekCompleteListener = new android.media.MediaPlayer.OnSeekCompleteListener() { + public void onSeekComplete(android.media.MediaPlayer mp) { + if (owningMediaPlayer != null) { + owningMediaPlayer.lock.lock(); + try { + lockMuteOnSeekCount.lock(); + try { + if (AndroidMediaPlayer.this.muteOnSeekCount > 0) { + AndroidMediaPlayer.this.muteOnSeekCount--; + } + else { + AndroidMediaPlayer.this.muteOnSeekCount = 0; + if (AndroidMediaPlayer.this.owningMediaPlayer.onSeekCompleteListener != null) { + owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer); + } + } + } + finally { + lockMuteOnSeekCount.unlock(); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + } + }; + + public AndroidMediaPlayer(com.aocate.media.MediaPlayer owningMediaPlayer, Context context) { + super(owningMediaPlayer, context); + + mp = new MediaPlayer(); + +// final ReentrantLock lock = new ReentrantLock(); +// Handler handler = new Handler(Looper.getMainLooper()) { +// @Override +// public void handleMessage(Message msg) { +// Log.d(AMP_TAG, "Instantiating new AndroidMediaPlayer from Handler"); +// lock.lock(); +// if (mp == null) { +// mp = new MediaPlayer(); +// } +// lock.unlock(); +// } +// }; +// +// long endTime = System.currentTimeMillis() + TIMEOUT_DURATION_MS; +// +// while (true) { +// // Retry messages until mp isn't null or it's time to give up +// handler.sendMessage(handler.obtainMessage()); +// if ((mp != null) +// || (endTime < System.currentTimeMillis())) { +// break; +// } +// try { +// Thread.sleep(50); +// } catch (InterruptedException e) { +// // TODO Auto-generated catch block +// e.printStackTrace(); +// } +// } + + if (mp == null) { + throw new IllegalStateException("Did not instantiate android.media.MediaPlayer successfully"); + } + + mp.setOnBufferingUpdateListener(this.onBufferingUpdateListener); + mp.setOnCompletionListener(this.onCompletionListener); + mp.setOnErrorListener(this.onErrorListener); + mp.setOnInfoListener(this.onInfoListener); + Log.d(AMP_TAG, " ++++++++++++++++++++++++++++++++ Setting prepared listener to this.onPreparedListener"); + mp.setOnPreparedListener(this.onPreparedListener); + mp.setOnSeekCompleteListener(this.onSeekCompleteListener); + } + + @Override + public boolean canSetPitch() { + return false; + } + + @Override + public boolean canSetSpeed() { + return false; + } + + @Override + public float getCurrentPitchStepsAdjustment() { + return 0; + } + + @Override + public int getCurrentPosition() { + owningMediaPlayer.lock.lock(); + try { + return mp.getCurrentPosition(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public float getCurrentSpeedMultiplier() { + return 1f; + } + + @Override + public int getDuration() { + owningMediaPlayer.lock.lock(); + try { + return mp.getDuration(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public float getMaxSpeedMultiplier() { + return 1f; + } + + @Override + public float getMinSpeedMultiplier() { + return 1f; + } + + @Override + public boolean isLooping() { + owningMediaPlayer.lock.lock(); + try { + return mp.isLooping(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public boolean isPlaying() { + owningMediaPlayer.lock.lock(); + try { + return mp.isPlaying(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void pause() { + owningMediaPlayer.lock.lock(); + try { + mp.pause(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void prepare() throws IllegalStateException, IOException { + owningMediaPlayer.lock.lock(); + Log.d(AMP_TAG, "prepare()"); + try { + mp.prepare(); + Log.d(AMP_TAG, "Finish prepare()"); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void prepareAsync() { + mp.prepareAsync(); + } + + @Override + public void release() { + owningMediaPlayer.lock.lock(); + try { + if (mp != null) { + Log.d(AMP_TAG, "mp.release()"); + mp.release(); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void reset() { + owningMediaPlayer.lock.lock(); + try { + mp.reset(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void seekTo(int msec) throws IllegalStateException { + owningMediaPlayer.lock.lock(); + try { + mp.setOnSeekCompleteListener(this.onSeekCompleteListener); + mp.seekTo(msec); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void setAudioStreamType(int streamtype) { + owningMediaPlayer.lock.lock(); + try { + mp.setAudioStreamType(streamtype); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void setDataSource(Context context, Uri uri) + throws IllegalArgumentException, IllegalStateException, IOException { + owningMediaPlayer.lock.lock(); + try { + Log.d(AMP_TAG, "setDataSource(context, " + uri.toString() + ")"); + mp.setDataSource(context, uri); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void setDataSource(String path) throws IllegalArgumentException, + IllegalStateException, IOException { + owningMediaPlayer.lock.lock(); + try { + Log.d(AMP_TAG, "setDataSource(" + path + ")"); + mp.setDataSource(path); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) { + // Can't! + } + + @Override + public void setLooping(boolean loop) { + owningMediaPlayer.lock.lock(); + try { + mp.setLooping(loop); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void setPitchStepsAdjustment(float pitchSteps) { + // Can't! + } + + @Override + public void setPlaybackPitch(float f) { + // Can't! + } + + @Override + public void setPlaybackSpeed(float f) { + // Can't! + Log.d(AMP_TAG, "setPlaybackSpeed(" + f + ")"); + } + + @Override + public void setSpeedAdjustmentAlgorithm(int algorithm) { + // Can't! + Log.d(AMP_TAG, "setSpeedAdjustmentAlgorithm(" + algorithm + ")"); + } + + @Override + public void setVolume(float leftVolume, float rightVolume) { + owningMediaPlayer.lock.lock(); + try { + mp.setVolume(leftVolume, rightVolume); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void setWakeMode(Context context, int mode) { + owningMediaPlayer.lock.lock(); + try { + if (mode != 0) { + mp.setWakeMode(context, mode); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void start() { + owningMediaPlayer.lock.lock(); + try { + mp.start(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + @Override + public void stop() { + owningMediaPlayer.lock.lock(); + try { + mp.stop(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } +} diff --git a/src/com/aocate/media/MediaPlayer.java b/src/com/aocate/media/MediaPlayer.java new file mode 100644 index 000000000..995dbbc51 --- /dev/null +++ b/src/com/aocate/media/MediaPlayer.java @@ -0,0 +1,1294 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.media; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.locks.ReentrantLock; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.media.AudioManager; +import android.net.Uri; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Handler.Callback; +import android.util.Log; + +public class MediaPlayer { + public interface OnBufferingUpdateListener { + public abstract void onBufferingUpdate(MediaPlayer arg0, int percent); + } + + public interface OnCompletionListener { + public abstract void onCompletion(MediaPlayer arg0); + } + + public interface OnErrorListener { + public abstract boolean onError(MediaPlayer arg0, int what, int extra); + } + + public interface OnInfoListener { + public abstract boolean onInfo(MediaPlayer arg0, int what, int extra); + } + + public interface OnPitchAdjustmentAvailableChangedListener { + /** + * + * @param arg0 + * The owning media player + * @param pitchAdjustmentAvailable + * True if pitch adjustment is available, false if not + */ + public abstract void onPitchAdjustmentAvailableChanged( + MediaPlayer arg0, boolean pitchAdjustmentAvailable); + } + + public interface OnPreparedListener { + public abstract void onPrepared(MediaPlayer arg0); + } + + public interface OnSeekCompleteListener { + public abstract void onSeekComplete(MediaPlayer arg0); + } + + public interface OnSpeedAdjustmentAvailableChangedListener { + /** + * + * @param arg0 + * The owning media player + * @param speedAdjustmentAvailable + * True if speed adjustment is available, false if not + */ + public abstract void onSpeedAdjustmentAvailableChanged( + MediaPlayer arg0, boolean speedAdjustmentAvailable); + } + + public enum State { + IDLE, INITIALIZED, PREPARED, STARTED, PAUSED, STOPPED, PREPARING, PLAYBACK_COMPLETED, END, ERROR + } + + private static Uri SPEED_ADJUSTMENT_MARKET_URI = Uri + .parse("market://details?id=com.aocate.presto"); + + private static Intent prestoMarketIntent = null; + + public static final int MEDIA_ERROR_SERVER_DIED = android.media.MediaPlayer.MEDIA_ERROR_SERVER_DIED; + public static final int MEDIA_ERROR_UNKNOWN = android.media.MediaPlayer.MEDIA_ERROR_UNKNOWN; + public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = android.media.MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK; + + /** + * Indicates whether the specified action can be used as an intent. This + * method queries the package manager for installed packages that can + * respond to an intent with the specified action. If no suitable package is + * found, this method returns false. + * + * @param context + * The application's environment. + * @param action + * The Intent action to check for availability. + * + * @return True if an Intent with the specified action can be sent and + * responded to, false otherwise. + */ + public static boolean isIntentAvailable(Context context, String action) { + final PackageManager packageManager = context.getPackageManager(); + final Intent intent = new Intent(action); + List<ResolveInfo> list = packageManager.queryIntentServices(intent, + PackageManager.MATCH_DEFAULT_ONLY); + return list.size() > 0; + } + + /** + * Indicates whether the Presto library is installed + * + * @param context + * The context to use to query the package manager. + * @return True if the Presto library is installed, false if not. + */ + public static boolean isPrestoLibraryInstalled(Context context) { + return isIntentAvailable(context, ServiceBackedMediaPlayer.INTENT_NAME); + } + + /** + * Return an Intent that opens the Android Market page for the speed + * alteration library + * + * @return The Intent for the Presto library on the Android Market + */ + public static Intent getPrestoMarketIntent() { + if (prestoMarketIntent == null) { + prestoMarketIntent = new Intent(Intent.ACTION_VIEW, + SPEED_ADJUSTMENT_MARKET_URI); + } + return prestoMarketIntent; + } + + /** + * Open the Android Market page for the Presto library + * + * @param context + * The context from which to open the Android Market page + */ + public static void openPrestoMarketIntent(Context context) { + context.startActivity(getPrestoMarketIntent()); + } + + private static final String MP_TAG = "AocateReplacementMediaPlayer"; + + private static final double PITCH_STEP_CONSTANT = 1.0594630943593; + + private AndroidMediaPlayer amp = null; + // This is whether speed adjustment should be enabled (by the Service) + // To avoid the Service entirely, set useService to false + protected boolean enableSpeedAdjustment = true; + private int lastKnownPosition = 0; + // In some cases, we're going to have to replace the + // android.media.MediaPlayer on the fly, and we don't want to touch the + // wrong media player, so lock it way too much. + ReentrantLock lock = new ReentrantLock(); + private int mAudioStreamType = AudioManager.STREAM_MUSIC; + private Context mContext; + private boolean mIsLooping = false; + private float mLeftVolume = 1f; + private float mPitchStepsAdjustment = 0f; + private float mRightVolume = 1f; + private float mSpeedMultiplier = 1f; + private int mWakeMode = 0; + MediaPlayerImpl mpi = null; + protected boolean pitchAdjustmentAvailable = false; + private ServiceBackedMediaPlayer sbmp = null; + protected boolean speedAdjustmentAvailable = false; + + private Handler mServiceDisconnectedHandler = null; + + // Some parts of state cannot be found by calling MediaPlayerImpl functions, + // so store our own state. This also helps copy state when changing + // implementations + State state = State.INITIALIZED; + String stringDataSource = null; + Uri uriDataSource = null; + private boolean useService = false; + + // Naming Convention for Listeners + // Most listeners can both be set by clients and called by MediaPlayImpls + // There are a few that have to do things in this class as well as calling + // the function. In all cases, onX is what is called by MediaPlayerImpl + // If there is work to be done in this class, then the listener that is + // set by setX is X (with the first letter lowercase). + OnBufferingUpdateListener onBufferingUpdateListener = null; + OnCompletionListener onCompletionListener = null; + OnErrorListener onErrorListener = null; + OnInfoListener onInfoListener = null; + + // Special case. Pitch adjustment ceases to be available when we switch + // to the android.media.MediaPlayer (though it is not guaranteed to be + // available when using the ServiceBackedMediaPlayer) + OnPitchAdjustmentAvailableChangedListener onPitchAdjustmentAvailableChangedListener = new OnPitchAdjustmentAvailableChangedListener() { + public void onPitchAdjustmentAvailableChanged(MediaPlayer arg0, + boolean pitchAdjustmentAvailable) { + lock.lock(); + try { + Log + .d( + MP_TAG, + "onPitchAdjustmentAvailableChangedListener.onPitchAdjustmentAvailableChanged being called"); + if (MediaPlayer.this.pitchAdjustmentAvailable != pitchAdjustmentAvailable) { + Log.d(MP_TAG, "Pitch adjustment state has changed from " + + MediaPlayer.this.pitchAdjustmentAvailable + + " to " + pitchAdjustmentAvailable); + MediaPlayer.this.pitchAdjustmentAvailable = pitchAdjustmentAvailable; + if (MediaPlayer.this.pitchAdjustmentAvailableChangedListener != null) { + MediaPlayer.this.pitchAdjustmentAvailableChangedListener + .onPitchAdjustmentAvailableChanged(arg0, + pitchAdjustmentAvailable); + } + } + } finally { + lock.unlock(); + } + } + }; + OnPitchAdjustmentAvailableChangedListener pitchAdjustmentAvailableChangedListener = null; + + MediaPlayer.OnPreparedListener onPreparedListener = new MediaPlayer.OnPreparedListener() { + public void onPrepared(MediaPlayer arg0) { + Log.d(MP_TAG, "onPreparedListener 242 setting state to PREPARED"); + MediaPlayer.this.state = State.PREPARED; + if (MediaPlayer.this.preparedListener != null) { + Log.d(MP_TAG, "Calling preparedListener"); + MediaPlayer.this.preparedListener.onPrepared(arg0); + } + Log.d(MP_TAG, "Wrap up onPreparedListener"); + } + }; + + OnPreparedListener preparedListener = null; + OnSeekCompleteListener onSeekCompleteListener = null; + + // Special case. Speed adjustment ceases to be available when we switch + // to the android.media.MediaPlayer (though it is not guaranteed to be + // available when using the ServiceBackedMediaPlayer) + OnSpeedAdjustmentAvailableChangedListener onSpeedAdjustmentAvailableChangedListener = new OnSpeedAdjustmentAvailableChangedListener() { + public void onSpeedAdjustmentAvailableChanged(MediaPlayer arg0, + boolean speedAdjustmentAvailable) { + lock.lock(); + try { + Log + .d( + MP_TAG, + "onSpeedAdjustmentAvailableChangedListener.onSpeedAdjustmentAvailableChanged being called"); + if (MediaPlayer.this.speedAdjustmentAvailable != speedAdjustmentAvailable) { + Log.d(MP_TAG, "Speed adjustment state has changed from " + + MediaPlayer.this.speedAdjustmentAvailable + + " to " + speedAdjustmentAvailable); + MediaPlayer.this.speedAdjustmentAvailable = speedAdjustmentAvailable; + if (MediaPlayer.this.speedAdjustmentAvailableChangedListener != null) { + MediaPlayer.this.speedAdjustmentAvailableChangedListener + .onSpeedAdjustmentAvailableChanged(arg0, + speedAdjustmentAvailable); + } + } + } finally { + lock.unlock(); + } + } + }; + OnSpeedAdjustmentAvailableChangedListener speedAdjustmentAvailableChangedListener = null; + + private int speedAdjustmentAlgorithm = SpeedAdjustmentAlgorithm.SONIC; + + public MediaPlayer(final Context context) { + this(context, true); + } + + public MediaPlayer(final Context context, boolean useService) { + this.mContext = context; + this.useService = useService; + + // So here's the major problem + // Sometimes the service won't exist or won't be connected, + // so start with an android.media.MediaPlayer, and when + // the service is connected, use that from then on + this.mpi = this.amp = new AndroidMediaPlayer(this, context); + + // setupMpi will go get the Service, if it can, then bring that + // implementation into sync + Log.d(MP_TAG, "setupMpi"); + setupMpi(context); + } + + private boolean invalidServiceConnectionConfiguration() { + if (!(this.mpi instanceof ServiceBackedMediaPlayer)) { + if (this.useService && isPrestoLibraryInstalled()) { + // In this case, the Presto library has been installed + // or something while playing sound + // We could be using the service, but we're not + Log.d(MP_TAG, "We could be using the service, but we're not 316"); + return true; + } + // If useService is false, then we shouldn't be using the SBMP + // If the Presto library isn't installed, ditto + Log.d(MP_TAG, "this.mpi is not a ServiceBackedMediaPlayer, but we couldn't use it anyway 321"); + return false; + } else { + assert (this.mpi instanceof ServiceBackedMediaPlayer); + if (this.useService && isPrestoLibraryInstalled()) { + // We should be using the service, and we are. Great! + Log.d(MP_TAG, "We could be using a ServiceBackedMediaPlayer and we are 327"); + return false; + } + // We're trying to use the service when we shouldn't, + // that's an invalid configuration + Log.d(MP_TAG, "We're trying to use a ServiceBackedMediaPlayer but we shouldn't be 332"); + return true; + } + } + + private void setupMpi(final Context context) { + lock.lock(); + try { + Log.d(MP_TAG, "setupMpi 336"); + // Check if the client wants to use the service at all, + // then if we're already using the right kind of media player + if (this.useService && isPrestoLibraryInstalled()) { + if ((this.mpi != null) + && (this.mpi instanceof ServiceBackedMediaPlayer)) { + Log.d(MP_TAG, "Already using ServiceBackedMediaPlayer"); + return; + } + if (this.sbmp == null) { + Log.d(MP_TAG, "Instantiating new ServiceBackedMediaPlayer 346"); + this.sbmp = new ServiceBackedMediaPlayer(this, context, + new ServiceConnection() { + public void onServiceConnected( + ComponentName className, + final IBinder service) { + Thread t = new Thread(new Runnable() { + public void run() { + // This lock probably isn't granular + // enough + MediaPlayer.this.lock.lock(); + Log.d(MP_TAG, + "onServiceConnected 257"); + try { + MediaPlayer.this + .switchMediaPlayerImpl( + MediaPlayer.this.amp, + MediaPlayer.this.sbmp); + Log.d(MP_TAG, "End onServiceConnected 362"); + } finally { + MediaPlayer.this.lock.unlock(); + } + } + }); + t.start(); + } + + public void onServiceDisconnected( + ComponentName className) { + MediaPlayer.this.lock.lock(); + try { + // Can't get any more useful information + // out of sbmp + if (MediaPlayer.this.sbmp != null) { + MediaPlayer.this.sbmp.release(); + } + // Unlike most other cases, sbmp gets set + // to null since there's nothing useful + // backing it now + MediaPlayer.this.sbmp = null; + + if (mServiceDisconnectedHandler == null) { + mServiceDisconnectedHandler = new Handler(new Callback() { + public boolean handleMessage(Message msg) { + // switchMediaPlayerImpl won't try to + // clone anything from null + lock.lock(); + try { + if (MediaPlayer.this.amp == null) { + // This should never be in this state + MediaPlayer.this.amp = new AndroidMediaPlayer( + MediaPlayer.this, + MediaPlayer.this.mContext); + } + // Use sbmp instead of null in case by some miracle it's + // been restored in the meantime + MediaPlayer.this.switchMediaPlayerImpl( + MediaPlayer.this.sbmp, + MediaPlayer.this.amp); + return true; + } + finally { + lock.unlock(); + } + } + }); + } + + // This code needs to execute on the + // original thread to instantiate + // the new object in the right place + mServiceDisconnectedHandler + .sendMessage( + mServiceDisconnectedHandler + .obtainMessage()); + // Note that we do NOT want to set + // useService. useService is about + // what the user wants, not what they + // get + } finally { + MediaPlayer.this.lock.unlock(); + } + } + } + ); + } + switchMediaPlayerImpl(this.amp, this.sbmp); + } else { + if ((this.mpi != null) + && (this.mpi instanceof AndroidMediaPlayer)) { + Log.d(MP_TAG, "Already using AndroidMediaPlayer"); + return; + } + if (this.amp == null) { + Log.d(MP_TAG, "Instantiating new AndroidMediaPlayer (this should be impossible)"); + this.amp = new AndroidMediaPlayer(this, context); + } + switchMediaPlayerImpl(this.sbmp, this.amp); + } + } finally { + lock.unlock(); + } + } + + private void switchMediaPlayerImpl(MediaPlayerImpl from, MediaPlayerImpl to) { + lock.lock(); + try { + Log.d(MP_TAG, "switchMediaPlayerImpl"); + if ((from == to) + // Same object, nothing to synchronize + || (to == null) + // Nothing to copy to (maybe this should throw an error?) + || ((to instanceof ServiceBackedMediaPlayer) && !((ServiceBackedMediaPlayer) to).isConnected()) + // ServiceBackedMediaPlayer hasn't yet connected, onServiceConnected will take care of the transition + || (MediaPlayer.this.state == State.END)) { + // State.END is after a release(), no further functions should + // be called on this class and from is likely to have problems + // retrieving state that won't be used anyway + return; + } + // Extract all that we can from the existing implementation + // and copy it to the new implementation + + Log.d(MP_TAG, "switchMediaPlayerImpl(), current state is " + + this.state.toString()); + + to.reset(); + + // Do this first so we don't have to prepare the same + // data file twice + to.setEnableSpeedAdjustment(MediaPlayer.this.enableSpeedAdjustment); + + // This is a reasonable place to set all of these, + // none of them require prepare() or the like first + to.setAudioStreamType(this.mAudioStreamType); + to.setSpeedAdjustmentAlgorithm(this.speedAdjustmentAlgorithm); + to.setLooping(this.mIsLooping); + to.setPitchStepsAdjustment(this.mPitchStepsAdjustment); + Log.d(MP_TAG, "Setting playback speed to " + this.mSpeedMultiplier); + to.setPlaybackSpeed(this.mSpeedMultiplier); + to.setVolume(MediaPlayer.this.mLeftVolume, + MediaPlayer.this.mRightVolume); + to.setWakeMode(this.mContext, this.mWakeMode); + + Log.d(MP_TAG, "asserting at least one data source is null"); + assert ((MediaPlayer.this.stringDataSource == null) || (MediaPlayer.this.uriDataSource == null)); + + if (uriDataSource != null) { + Log.d(MP_TAG, "switchMediaPlayerImpl(): uriDataSource != null"); + try { + to.setDataSource(this.mContext, uriDataSource); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + if (stringDataSource != null) { + Log.d(MP_TAG, + "switchMediaPlayerImpl(): stringDataSource != null"); + try { + to.setDataSource(stringDataSource); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + if ((this.state == State.PREPARED) + || (this.state == State.PREPARING) + || (this.state == State.PAUSED) + || (this.state == State.STOPPED) + || (this.state == State.STARTED) + || (this.state == State.PLAYBACK_COMPLETED)) { + Log.d(MP_TAG, "switchMediaPlayerImpl(): prepare and seek"); + // Use prepare here instead of prepareAsync so that + // we wait for it to be ready before we try to use it + try { + to.muteNextOnPrepare(); + to.prepare(); + } catch (IllegalStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + int seekPos = 0; + if (from != null) { + seekPos = from.getCurrentPosition(); + } else if (this.lastKnownPosition < to.getDuration()) { + // This can happen if the Service unexpectedly + // disconnected. Because it would result in too much + // information being passed around, we don't constantly + // poll for the lastKnownPosition, but we'll save it + // when getCurrentPosition is called + seekPos = this.lastKnownPosition; + } + to.muteNextSeek(); + to.seekTo(seekPos); + } + if ((from != null) + && from.isPlaying()) { + from.pause(); + } + if ((this.state == State.STARTED) + || (this.state == State.PAUSED) + || (this.state == State.STOPPED)) { + Log.d(MP_TAG, "switchMediaPlayerImpl(): start"); + if (to != null) { + to.start(); + } + } + + if (this.state == State.PAUSED) { + Log.d(MP_TAG, "switchMediaPlayerImpl(): paused"); + if (to != null) { + to.pause(); + } + } else if (this.state == State.STOPPED) { + Log.d(MP_TAG, "switchMediaPlayerImpl(): stopped"); + if (to != null) { + to.stop(); + } + } + + this.mpi = to; + + // Cheating here by relying on the side effect in + // on(Pitch|Speed)AdjustmentAvailableChanged + if ((to.canSetPitch() != this.pitchAdjustmentAvailable) + && (this.onPitchAdjustmentAvailableChangedListener != null)) { + this.onPitchAdjustmentAvailableChangedListener + .onPitchAdjustmentAvailableChanged(this, to + .canSetPitch()); + } + if ((to.canSetSpeed() != this.speedAdjustmentAvailable) + && (this.onSpeedAdjustmentAvailableChangedListener != null)) { + this.onSpeedAdjustmentAvailableChangedListener + .onSpeedAdjustmentAvailableChanged(this, to + .canSetSpeed()); + } + Log.d(MP_TAG, "switchMediaPlayerImpl() 625 " + this.state.toString()); + } finally { + lock.unlock(); + } + } + + /** + * Returns true if pitch can be changed at this moment + * + * @return True if pitch can be changed + */ + public boolean canSetPitch() { + lock.lock(); + try { + return this.mpi.canSetPitch(); + } finally { + lock.unlock(); + } + } + + /** + * Returns true if speed can be changed at this moment + * + * @return True if speed can be changed + */ + public boolean canSetSpeed() { + lock.lock(); + try { + return this.mpi.canSetSpeed(); + } finally { + lock.unlock(); + } + } + + protected void finalize() throws Throwable { + lock.lock(); + try { + Log.d(MP_TAG, "finalize() 626"); + this.release(); + } finally { + lock.unlock(); + } + } + + /** + * Returns the number of steps (in a musical scale) by which playback is + * currently shifted. When greater than zero, pitch is shifted up. When less + * than zero, pitch is shifted down. + * + * @return The number of steps pitch is currently shifted by + */ + public float getCurrentPitchStepsAdjustment() { + lock.lock(); + try { + return this.mpi.getCurrentPitchStepsAdjustment(); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.getCurrentPosition() + * Accurate only to frame size of encoded data (26 ms for MP3s) + * + * @return Current position (in milliseconds) + */ + public int getCurrentPosition() { + lock.lock(); + try { + return (this.lastKnownPosition = this.mpi.getCurrentPosition()); + } finally { + lock.unlock(); + } + } + + /** + * Returns the current speed multiplier. Defaults to 1.0 (normal speed) + * + * @return The current speed multiplier + */ + public float getCurrentSpeedMultiplier() { + lock.lock(); + try { + return this.mpi.getCurrentSpeedMultiplier(); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.getDuration() + * + * @return Length of the track (in milliseconds) + */ + public int getDuration() { + lock.lock(); + try { + return this.mpi.getDuration(); + } finally { + lock.unlock(); + } + } + + /** + * Get the maximum value that can be passed to setPlaybackSpeed + * + * @return The maximum speed multiplier + */ + public float getMaxSpeedMultiplier() { + lock.lock(); + try { + return this.mpi.getMaxSpeedMultiplier(); + } finally { + lock.unlock(); + } + } + + /** + * Get the minimum value that can be passed to setPlaybackSpeed + * + * @return The minimum speed multiplier + */ + public float getMinSpeedMultiplier() { + lock.lock(); + try { + return this.mpi.getMinSpeedMultiplier(); + } finally { + lock.unlock(); + } + } + + /** + * Gets the version code of the backing service + * @return -1 if ServiceBackedMediaPlayer is not used, 0 if the service is not + * connected, otherwise the version code retrieved from the service + */ + public int getServiceVersionCode() { + lock.lock(); + try { + if (this.mpi instanceof ServiceBackedMediaPlayer) { + return ((ServiceBackedMediaPlayer) this.mpi).getServiceVersionCode(); + } + else { + return -1; + } + } + finally { + lock.unlock(); + } + } + + /** + * Gets the version name of the backing service + * @return null if ServiceBackedMediaPlayer is not used, empty string if + * the service is not connected, otherwise the version name retrieved from + * the service + */ + public String getServiceVersionName() { + lock.lock(); + try { + if (this.mpi instanceof ServiceBackedMediaPlayer) { + return ((ServiceBackedMediaPlayer) this.mpi).getServiceVersionName(); + } + else { + return null; + } + } + finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.isLooping() + * + * @return True if the track is looping + */ + public boolean isLooping() { + lock.lock(); + try { + return this.mpi.isLooping(); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.isPlaying() + * + * @return True if the track is playing + */ + public boolean isPlaying() { + lock.lock(); + try { + return this.mpi.isPlaying(); + } finally { + lock.unlock(); + } + } + + /** + * Returns true if this MediaPlayer has access to the Presto + * library + * + * @return True if the Presto library is installed + */ + public boolean isPrestoLibraryInstalled() { + if ((this.mpi == null) || (this.mpi.mContext == null)) { + return false; + } + return isPrestoLibraryInstalled(this.mpi.mContext); + } + + /** + * Open the Android Market page in the same context as this MediaPlayer + */ + public void openPrestoMarketIntent() { + if ((this.mpi != null) && (this.mpi.mContext != null)) { + openPrestoMarketIntent(this.mpi.mContext); + } + } + + /** + * Functions identically to android.media.MediaPlayer.pause() Pauses the + * track + */ + public void pause() { + lock.lock(); + try { + if (invalidServiceConnectionConfiguration()) { + setupMpi(this.mpi.mContext); + } + this.state = State.PAUSED; + this.mpi.pause(); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.prepare() Prepares the + * track. This or prepareAsync must be called before start() + */ + public void prepare() throws IllegalStateException, IOException { + lock.lock(); + try { + Log.d(MP_TAG, "prepare() 746 using " + ((this.mpi == null) ? "null (this shouldn't happen)" : this.mpi.getClass().toString()) + " state " + this.state.toString()); + Log.d(MP_TAG, "onPreparedListener is: " + ((this.onPreparedListener == null) ? "null" : "non-null")); + Log.d(MP_TAG, "preparedListener is: " + ((this.preparedListener == null) ? "null" : "non-null")); + if (invalidServiceConnectionConfiguration()) { + setupMpi(this.mpi.mContext); + } + this.mpi.prepare(); + this.state = State.PREPARED; + Log.d(MP_TAG, "prepare() finished 778"); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.prepareAsync() + * Prepares the track. This or prepare must be called before start() + */ + public void prepareAsync() { + lock.lock(); + try { + Log.d(MP_TAG, "prepareAsync() 779"); + if (invalidServiceConnectionConfiguration()) { + setupMpi(this.mpi.mContext); + } + this.state = State.PREPARING; + this.mpi.prepareAsync(); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.release() Releases the + * underlying resources used by the media player. + */ + public void release() { + lock.lock(); + try { + Log.d(MP_TAG, "Releasing MediaPlayer 791"); + + this.state = State.END; + if (this.amp != null) { + this.amp.release(); + } + if (this.sbmp != null) { + this.sbmp.release(); + } + + this.onBufferingUpdateListener = null; + this.onCompletionListener = null; + this.onErrorListener = null; + this.onInfoListener = null; + this.preparedListener = null; + this.onPitchAdjustmentAvailableChangedListener = null; + this.pitchAdjustmentAvailableChangedListener = null; + Log.d(MP_TAG, "Setting onSeekCompleteListener to null 871"); + this.onSeekCompleteListener = null; + this.onSpeedAdjustmentAvailableChangedListener = null; + this.speedAdjustmentAvailableChangedListener = null; + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.reset() Resets the + * track to idle state + */ + public void reset() { + lock.lock(); + try { + this.state = State.IDLE; + this.stringDataSource = null; + this.uriDataSource = null; + this.mpi.reset(); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.seekTo(int msec) Seeks + * to msec in the track + */ + public void seekTo(int msec) throws IllegalStateException { + lock.lock(); + try { + this.mpi.seekTo(msec); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setAudioStreamType(int + * streamtype) Sets the audio stream type. + */ + public void setAudioStreamType(int streamtype) { + lock.lock(); + try { + this.mAudioStreamType = streamtype; + this.mpi.setAudioStreamType(streamtype); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setDataSource(Context + * context, Uri uri) Sets uri as data source in the context given + */ + public void setDataSource(Context context, Uri uri) + throws IllegalArgumentException, IllegalStateException, IOException { + lock.lock(); + try { + Log.d(MP_TAG, "In setDataSource(context, " + uri.toString() + "), using " + this.mpi.getClass().toString()); + if (invalidServiceConnectionConfiguration()) { + setupMpi(this.mpi.mContext); + } + this.state = State.INITIALIZED; + this.stringDataSource = null; + this.uriDataSource = uri; + this.mpi.setDataSource(context, uri); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setDataSource(String + * path) Sets the data source of the track to a file given. + */ + public void setDataSource(String path) throws IllegalArgumentException, + IllegalStateException, IOException { + lock.lock(); + try { + Log.d(MP_TAG, "In setDataSource(context, " + path + ")"); + if (invalidServiceConnectionConfiguration()) { + setupMpi(this.mpi.mContext); + } + this.state = State.INITIALIZED; + this.stringDataSource = path; + this.uriDataSource = null; + this.mpi.setDataSource(path); + } finally { + lock.unlock(); + } + } + + /** + * Sets whether to use speed adjustment or not. Speed adjustment on is more + * computation-intensive than with it off. + * + * @param enableSpeedAdjustment + * Whether speed adjustment should be supported. + */ + public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) { + lock.lock(); + try { + this.enableSpeedAdjustment = enableSpeedAdjustment; + this.mpi.setEnableSpeedAdjustment(enableSpeedAdjustment); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setLooping(boolean + * loop) Sets the track to loop infinitely if loop is true, play once if + * loop is false + */ + public void setLooping(boolean loop) { + lock.lock(); + try { + this.mIsLooping = loop; + this.mpi.setLooping(loop); + } finally { + lock.unlock(); + } + } + + /** + * Sets the number of steps (in a musical scale) by which playback is + * currently shifted. When greater than zero, pitch is shifted up. When less + * than zero, pitch is shifted down. + * + * @param pitchSteps + * The number of steps by which to shift playback + */ + public void setPitchStepsAdjustment(float pitchSteps) { + lock.lock(); + try { + this.mPitchStepsAdjustment = pitchSteps; + this.mpi.setPitchStepsAdjustment(pitchSteps); + } finally { + lock.unlock(); + } + } + + /** + * Set the algorithm to use for changing the speed and pitch of audio + * See SpeedAdjustmentAlgorithm constants for more details + * @param algorithm The algorithm to use. + */ + public void setSpeedAdjustmentAlgorithm(int algorithm) { + lock.lock(); + try { + this.speedAdjustmentAlgorithm = algorithm; + if (this.mpi != null) { + this.mpi.setSpeedAdjustmentAlgorithm(algorithm); + } + } + finally { + lock.unlock(); + } + } + + private static float getPitchStepsAdjustment(float pitch) { + return (float) (Math.log(pitch) / (2 * Math.log(PITCH_STEP_CONSTANT))); + } + + /** + * Sets the percentage by which pitch is currently shifted. When greater + * than zero, pitch is shifted up. When less than zero, pitch is shifted + * down + * + * @param f + * The percentage to shift pitch + */ + public void setPlaybackPitch(float pitch) { + lock.lock(); + try { + this.mPitchStepsAdjustment = getPitchStepsAdjustment(pitch); + this.mpi.setPlaybackPitch(pitch); + } finally { + lock.unlock(); + } + } + + /** + * Set playback speed. 1.0 is normal speed, 2.0 is double speed, and so on. + * Speed should never be set to 0 or below. + * + * @param f + * The speed multiplier to use for further playback + */ + public void setPlaybackSpeed(float f) { + lock.lock(); + try { + this.mSpeedMultiplier = f; + this.mpi.setPlaybackSpeed(f); + } finally { + lock.unlock(); + } + } + + /** + * Sets whether to use speed adjustment or not. Speed adjustment on is more + * computation-intensive than with it off. + * + * @param enableSpeedAdjustment + * Whether speed adjustment should be supported. + */ + public void setUseService(boolean useService) { + lock.lock(); + try { + this.useService = useService; + setupMpi(this.mpi.mContext); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setVolume(float + * leftVolume, float rightVolume) Sets the stereo volume + */ + public void setVolume(float leftVolume, float rightVolume) { + lock.lock(); + try { + this.mLeftVolume = leftVolume; + this.mRightVolume = rightVolume; + this.mpi.setVolume(leftVolume, rightVolume); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setWakeMode(Context + * context, int mode) Acquires a wake lock in the context given. You must + * request the appropriate permissions in your AndroidManifest.xml file. + */ + public void setWakeMode(Context context, int mode) { + lock.lock(); + try { + this.mWakeMode = mode; + this.mpi.setWakeMode(context, mode); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to + * android.media.MediaPlayer.setOnCompletionListener(OnCompletionListener + * listener) Sets a listener to be used when a track completes playing. + */ + public void setOnBufferingUpdateListener(OnBufferingUpdateListener listener) { + lock.lock(); + try { + this.onBufferingUpdateListener = listener; + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to + * android.media.MediaPlayer.setOnCompletionListener(OnCompletionListener + * listener) Sets a listener to be used when a track completes playing. + */ + public void setOnCompletionListener(OnCompletionListener listener) { + lock.lock(); + try { + this.onCompletionListener = listener; + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to + * android.media.MediaPlayer.setOnErrorListener(OnErrorListener listener) + * Sets a listener to be used when a track encounters an error. + */ + public void setOnErrorListener(OnErrorListener listener) { + lock.lock(); + try { + this.onErrorListener = listener; + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to + * android.media.MediaPlayer.setOnInfoListener(OnInfoListener listener) Sets + * a listener to be used when a track has info. + */ + public void setOnInfoListener(OnInfoListener listener) { + lock.lock(); + try { + this.onInfoListener = listener; + } finally { + lock.unlock(); + } + } + + /** + * Sets a listener that will fire when pitch adjustment becomes available or + * stops being available + */ + public void setOnPitchAdjustmentAvailableChangedListener( + OnPitchAdjustmentAvailableChangedListener listener) { + lock.lock(); + try { + this.pitchAdjustmentAvailableChangedListener = listener; + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to + * android.media.MediaPlayer.setOnPreparedListener(OnPreparedListener + * listener) Sets a listener to be used when a track finishes preparing. + */ + public void setOnPreparedListener(OnPreparedListener listener) { + lock.lock(); + Log.d(MP_TAG, " ++++++++++++++++++++++++++++++++++++++++++++ setOnPreparedListener"); + try { + this.preparedListener = listener; + // For this one, we do not explicitly set the MediaPlayer or the + // Service listener. This is because in addition to calling the + // listener provided by the client, it's necessary to change + // state to PREPARED. See prepareAsync for implementation details + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to + * android.media.MediaPlayer.setOnSeekCompleteListener + * (OnSeekCompleteListener listener) Sets a listener to be used when a track + * finishes seeking. + */ + public void setOnSeekCompleteListener(OnSeekCompleteListener listener) { + lock.lock(); + try { + this.onSeekCompleteListener = listener; + } finally { + lock.unlock(); + } + } + + /** + * Sets a listener that will fire when speed adjustment becomes available or + * stops being available + */ + public void setOnSpeedAdjustmentAvailableChangedListener( + OnSpeedAdjustmentAvailableChangedListener listener) { + lock.lock(); + try { + this.speedAdjustmentAvailableChangedListener = listener; + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.start() Starts a track + * playing + */ + public void start() { + lock.lock(); + try { + Log.d(MP_TAG, "start() 1149"); + if (invalidServiceConnectionConfiguration()) { + setupMpi(this.mpi.mContext); + } + this.state = State.STARTED; + Log.d(MP_TAG, "start() 1154"); + this.mpi.start(); + } finally { + lock.unlock(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.stop() Stops a track + * playing and resets its position to the start. + */ + public void stop() { + lock.lock(); + try { + if (invalidServiceConnectionConfiguration()) { + setupMpi(this.mpi.mContext); + } + this.state = State.STOPPED; + this.mpi.stop(); + } finally { + lock.unlock(); + } + } +}
\ No newline at end of file diff --git a/src/com/aocate/media/MediaPlayerImpl.java b/src/com/aocate/media/MediaPlayerImpl.java new file mode 100644 index 000000000..856ab47ce --- /dev/null +++ b/src/com/aocate/media/MediaPlayerImpl.java @@ -0,0 +1,118 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.media; + +import java.io.IOException; +import java.util.concurrent.locks.ReentrantLock; + +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +public abstract class MediaPlayerImpl { + private static final String MPI_TAG = "AocateMediaPlayerImpl"; + protected final MediaPlayer owningMediaPlayer; + protected final Context mContext; + protected int muteOnPreparedCount = 0; + protected int muteOnSeekCount = 0; + + public MediaPlayerImpl(MediaPlayer owningMediaPlayer, Context context) { + this.owningMediaPlayer = owningMediaPlayer; + + this.mContext = context; + } + + public abstract boolean canSetPitch(); + + public abstract boolean canSetSpeed(); + + public abstract float getCurrentPitchStepsAdjustment(); + + public abstract int getCurrentPosition(); + + public abstract float getCurrentSpeedMultiplier(); + + public abstract int getDuration(); + + public abstract float getMaxSpeedMultiplier(); + + public abstract float getMinSpeedMultiplier(); + + public abstract boolean isLooping(); + + public abstract boolean isPlaying(); + + public abstract void pause(); + + public abstract void prepare() throws IllegalStateException, IOException; + + public abstract void prepareAsync(); + + public abstract void release(); + + public abstract void reset(); + + public abstract void seekTo(int msec) throws IllegalStateException; + + public abstract void setAudioStreamType(int streamtype); + + public abstract void setDataSource(Context context, Uri uri) throws IllegalArgumentException, IllegalStateException, IOException; + + public abstract void setDataSource(String path) throws IllegalArgumentException, IllegalStateException, IOException; + + public abstract void setEnableSpeedAdjustment(boolean enableSpeedAdjustment); + + public abstract void setLooping(boolean loop); + + public abstract void setPitchStepsAdjustment(float pitchSteps); + + public abstract void setPlaybackPitch(float f); + + public abstract void setPlaybackSpeed(float f); + + public abstract void setSpeedAdjustmentAlgorithm(int algorithm); + + public abstract void setVolume(float leftVolume, float rightVolume); + + public abstract void setWakeMode(Context context, int mode); + + public abstract void start(); + + public abstract void stop(); + + protected ReentrantLock lockMuteOnPreparedCount = new ReentrantLock(); + public void muteNextOnPrepare() { + lockMuteOnPreparedCount.lock(); + Log.d(MPI_TAG, "muteNextOnPrepare()"); + try { + this.muteOnPreparedCount++; + } + finally { + lockMuteOnPreparedCount.unlock(); + } + } + + protected ReentrantLock lockMuteOnSeekCount = new ReentrantLock(); + public void muteNextSeek() { + lockMuteOnSeekCount.lock(); + Log.d(MPI_TAG, "muteNextOnSeek()"); + try { + this.muteOnSeekCount++; + } + finally { + lockMuteOnSeekCount.unlock(); + } + } +} diff --git a/src/com/aocate/media/ServiceBackedMediaPlayer.java b/src/com/aocate/media/ServiceBackedMediaPlayer.java new file mode 100644 index 000000000..ef4572d33 --- /dev/null +++ b/src/com/aocate/media/ServiceBackedMediaPlayer.java @@ -0,0 +1,1170 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.media; + +import java.io.IOException; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.media.AudioManager; +import android.net.Uri; +import android.os.IBinder; +import android.os.PowerManager; +import android.os.RemoteException; +import android.os.PowerManager.WakeLock; +import android.util.Log; + +import com.aocate.media.MediaPlayer.State; +import com.aocate.presto.service.IDeathCallback_0_8; +import com.aocate.presto.service.IOnBufferingUpdateListenerCallback_0_8; +import com.aocate.presto.service.IOnCompletionListenerCallback_0_8; +import com.aocate.presto.service.IOnErrorListenerCallback_0_8; +import com.aocate.presto.service.IOnInfoListenerCallback_0_8; +import com.aocate.presto.service.IOnPitchAdjustmentAvailableChangedListenerCallback_0_8; +import com.aocate.presto.service.IOnPreparedListenerCallback_0_8; +import com.aocate.presto.service.IOnSeekCompleteListenerCallback_0_8; +import com.aocate.presto.service.IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8; +import com.aocate.presto.service.IPlayMedia_0_8; + +/** + * Class for connecting to remote speed-altering, media playing Service + * Note that there is unusually high coupling between MediaPlayer and this + * class. This is an unfortunate compromise, since the alternative was to + * track state in two different places in this code (plus the internal state + * of the remote media player). + * @author aocate + * + */ +public class ServiceBackedMediaPlayer extends MediaPlayerImpl { + static final String INTENT_NAME = "com.aocate.intent.PLAY_AUDIO_ADJUST_SPEED_0_8"; + + private static final String SBMP_TAG = "AocateServiceBackedMediaPlayer"; + + private ServiceConnection mPlayMediaServiceConnection = null; + protected IPlayMedia_0_8 pmInterface = null; + private Intent playMediaServiceIntent = null; + // In some cases, we're going to have to replace the + // android.media.MediaPlayer on the fly, and we don't want to touch the + // wrong media player. + + private long sessionId = 0; + private boolean isErroring = false; + private int mAudioStreamType = AudioManager.STREAM_MUSIC; + + private WakeLock mWakeLock = null; + + // So here's the major problem + // Sometimes the service won't exist or won't be connected, + // so start with an android.media.MediaPlayer, and when + // the service is connected, use that from then on + public ServiceBackedMediaPlayer(MediaPlayer owningMediaPlayer, final Context context, final ServiceConnection serviceConnection) { + super(owningMediaPlayer, context); + Log.d(SBMP_TAG, "Instantiating ServiceBackedMediaPlayer 87"); + this.playMediaServiceIntent = + new Intent(INTENT_NAME); + this.mPlayMediaServiceConnection = new ServiceConnection() { + public void onServiceConnected(ComponentName name, IBinder service) { + IPlayMedia_0_8 tmpPlayMediaInterface = IPlayMedia_0_8.Stub.asInterface((IBinder) service); + + Log.d(SBMP_TAG, "Setting up pmInterface 94"); + if (ServiceBackedMediaPlayer.this.sessionId == 0) { + try { + // The IDeathCallback isn't a conventional callback. + // It exists so that if the client ceases to exist, + // the Service becomes aware of that and can shut + // down whatever it needs to shut down + ServiceBackedMediaPlayer.this.sessionId = tmpPlayMediaInterface.startSession(new IDeathCallback_0_8.Stub() { + }); + // This is really bad if this fails + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + Log.d(SBMP_TAG, "Assigning pmInterface"); + + ServiceBackedMediaPlayer.this.setOnBufferingUpdateCallback(tmpPlayMediaInterface); + ServiceBackedMediaPlayer.this.setOnCompletionCallback(tmpPlayMediaInterface); + ServiceBackedMediaPlayer.this.setOnErrorCallback(tmpPlayMediaInterface); + ServiceBackedMediaPlayer.this.setOnInfoCallback(tmpPlayMediaInterface); + ServiceBackedMediaPlayer.this.setOnPitchAdjustmentAvailableChangedListener(tmpPlayMediaInterface); + ServiceBackedMediaPlayer.this.setOnPreparedCallback(tmpPlayMediaInterface); + ServiceBackedMediaPlayer.this.setOnSeekCompleteCallback(tmpPlayMediaInterface); + ServiceBackedMediaPlayer.this.setOnSpeedAdjustmentAvailableChangedCallback(tmpPlayMediaInterface); + + // In order to avoid race conditions from the sessionId or listener not being assigned + pmInterface = tmpPlayMediaInterface; + + Log.d(SBMP_TAG, "Invoking onServiceConnected"); + serviceConnection.onServiceConnected(name, service); + } + + public void onServiceDisconnected(ComponentName name) { + Log.d(SBMP_TAG, "onServiceDisconnected 114"); + + pmInterface = null; + + sessionId = 0; + + serviceConnection.onServiceDisconnected(name); + } + }; + + Log.d(SBMP_TAG, "Connecting PlayMediaService 124"); + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private boolean ConnectPlayMediaService() { + Log.d(SBMP_TAG, "ConnectPlayMediaService()"); + + if (MediaPlayer.isIntentAvailable(mContext, INTENT_NAME)) { + Log.d(SBMP_TAG, INTENT_NAME + " is available"); + if (pmInterface == null) { + try { + Log.d(SBMP_TAG, "Binding service"); + return mContext.bindService(playMediaServiceIntent, mPlayMediaServiceConnection, Context.BIND_AUTO_CREATE); + } catch (Exception e) { + return false; + } + } else { + Log.d(SBMP_TAG, "Service already bound"); + return true; + } + } + else { + Log.d(SBMP_TAG, INTENT_NAME + " is not available"); + return false; + } + } + + /** + * Returns true if pitch can be changed at this moment + * @return True if pitch can be changed + */ + @Override + public boolean canSetPitch() { + Log.d(SBMP_TAG, "canSetPitch() 155"); + + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set pitch if the service isn't connected + try { + return pmInterface.canSetPitch(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + return false; + } + + /** + * Returns true if speed can be changed at this moment + * @return True if speed can be changed + */ + @Override + public boolean canSetSpeed() { + Log.d(SBMP_TAG, "canSetSpeed() 180"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the service isn't connected + try { + return pmInterface.canSetSpeed(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + return false; + } + + void error(int what, int extra) { + owningMediaPlayer.lock.lock(); + Log.e(SBMP_TAG, "error(" + what + ", " + extra + ")"); + try { + if (!this.isErroring) { + this.isErroring = true; + owningMediaPlayer.state = State.ERROR; + if (owningMediaPlayer.onErrorListener != null) { + if (owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra)) { + return; + } + } + if (owningMediaPlayer.onCompletionListener != null) { + owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer); + } + } + } + finally { + this.isErroring = false; + owningMediaPlayer.lock.unlock(); + } + } + + protected void finalize() throws Throwable { + owningMediaPlayer.lock.lock(); + try { + Log.d(SBMP_TAG, "finalize() 224"); + this.release(); + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + /** + * Returns the number of steps (in a musical scale) by which playback is + * currently shifted. When greater than zero, pitch is shifted up. + * When less than zero, pitch is shifted down. + * @return The number of steps pitch is currently shifted by + */ + @Override + public float getCurrentPitchStepsAdjustment() { + Log.d(SBMP_TAG, "getCurrentPitchStepsAdjustment() 240"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set pitch if the service isn't connected + try { + return pmInterface.getCurrentPitchStepsAdjustment( + ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + return 0f; + } + + /** + * Functions identically to android.media.MediaPlayer.getCurrentPosition() + * @return Current position (in milliseconds) + */ + @Override + public int getCurrentPosition() { + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + return pmInterface.getCurrentPosition( + ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + return 0; + } + + /** + * Returns the current speed multiplier. Defaults to 1.0 (normal speed) + * @return The current speed multiplier + */ + @Override + public float getCurrentSpeedMultiplier() { + Log.d(SBMP_TAG, "getCurrentSpeedMultiplier() 286"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the service isn't connected + try { + return pmInterface.getCurrentSpeedMultiplier( + ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + return 1; + } + + /** + * Functions identically to android.media.MediaPlayer.getDuration() + * @return Length of the track (in milliseconds) + */ + @Override + public int getDuration() { + Log.d(SBMP_TAG, "getDuration() 311"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + return pmInterface.getDuration(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + return 0; + } + + /** + * Get the maximum value that can be passed to setPlaybackSpeed + * @return The maximum speed multiplier + */ + @Override + public float getMaxSpeedMultiplier() { + Log.d(SBMP_TAG, "getMaxSpeedMultiplier() 332"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the Service isn't connected + try { + return pmInterface.getMaxSpeedMultiplier( + ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + return 1f; + } + + /** + * Get the minimum value that can be passed to setPlaybackSpeed + * @return The minimum speed multiplier + */ + @Override + public float getMinSpeedMultiplier() { + Log.d(SBMP_TAG, "getMinSpeedMultiplier() 357"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the Service isn't connected + try { + return pmInterface.getMinSpeedMultiplier( + ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + return 1f; + } + + public int getServiceVersionCode() { + Log.d(SBMP_TAG, "getVersionCode"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + return pmInterface.getVersionCode(); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + return 0; + } + + public String getServiceVersionName() { + Log.d(SBMP_TAG, "getVersionName"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + return pmInterface.getVersionName(); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + return ""; + } + + public boolean isConnected() { + return (pmInterface != null); + } + + /** + * Functions identically to android.media.MediaPlayer.isLooping() + * @return True if the track is looping + */ + @Override + public boolean isLooping() { + Log.d(SBMP_TAG, "isLooping() 382"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + return pmInterface.isLooping(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + return false; + } + + /** + * Functions identically to android.media.MediaPlayer.isPlaying() + * @return True if the track is playing + */ + @Override + public boolean isPlaying() { + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + try { + return pmInterface.isPlaying(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + return false; + } + + /** + * Functions identically to android.media.MediaPlayer.pause() + * Pauses the track + */ + @Override + public void pause() { + Log.d(SBMP_TAG, "pause() 424"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.pause(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.prepare() + * Prepares the track. This or prepareAsync must be called before start() + */ + @Override + public void prepare() throws IllegalStateException, IOException { + Log.d(SBMP_TAG, "prepare() 444"); + Log.d(SBMP_TAG, "onPreparedCallback is: " + ((this.mOnPreparedCallback == null) ? "null" : "non-null")); + if (pmInterface == null) { + Log.d(SBMP_TAG, "prepare: pmInterface is null"); + if (!ConnectPlayMediaService()) { + Log.d(SBMP_TAG, "prepare: Failed to connect play media service"); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + Log.d(SBMP_TAG, "prepare: pmInterface isn't null"); + try { + Log.d(SBMP_TAG, "prepare: Remote invoke pmInterface.prepare(" + ServiceBackedMediaPlayer.this.sessionId + ")"); + pmInterface.prepare(ServiceBackedMediaPlayer.this.sessionId); + Log.d(SBMP_TAG, "prepare: prepared"); + } catch (RemoteException e) { + Log.d(SBMP_TAG, "prepare: RemoteException"); + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + Log.d(SBMP_TAG, "Done with prepare()"); + } + + /** + * Functions identically to android.media.MediaPlayer.prepareAsync() + * Prepares the track. This or prepare must be called before start() + */ + @Override + public void prepareAsync() { + Log.d(SBMP_TAG, "prepareAsync() 469"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.prepareAsync(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.release() + * Releases the underlying resources used by the media player. + */ + @Override + public void release() { + Log.d(SBMP_TAG, "release() 492"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + Log.d(SBMP_TAG, "release() 500"); + try { + pmInterface.release(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + mContext.unbindService(this.mPlayMediaServiceConnection); + // Don't try to keep awake (if we were) + this.setWakeMode(mContext, 0); + pmInterface = null; + this.sessionId = 0; + } + + if ((this.mWakeLock != null) && this.mWakeLock.isHeld()) { + Log.d(SBMP_TAG, "Releasing wakelock"); + this.mWakeLock.release(); + } + } + + /** + * Functions identically to android.media.MediaPlayer.reset() + * Resets the track to idle state + */ + @Override + public void reset() { + Log.d(SBMP_TAG, "reset() 523"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.reset(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.seekTo(int msec) + * Seeks to msec in the track + */ + @Override + public void seekTo(int msec) throws IllegalStateException { + Log.d(SBMP_TAG, "seekTo(" + msec + ")"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.seekTo(ServiceBackedMediaPlayer.this.sessionId, msec); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setAudioStreamType(int streamtype) + * Sets the audio stream type. + */ + @Override + public void setAudioStreamType(int streamtype) { + Log.d(SBMP_TAG, "setAudioStreamType(" + streamtype + ")"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.setAudioStreamType( + ServiceBackedMediaPlayer.this.sessionId, + this.mAudioStreamType); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + + /** + * Functions identically to android.media.MediaPlayer.setDataSource(Context context, Uri uri) + * Sets uri as data source in the context given + */ + @Override + public void setDataSource(Context context, Uri uri) throws IllegalArgumentException, IllegalStateException, IOException { + Log.d(SBMP_TAG, "setDataSource(context, uri)"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.setDataSourceUri( + ServiceBackedMediaPlayer.this.sessionId, + uri); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setDataSource(String path) + * Sets the data source of the track to a file given. + */ + @Override + public void setDataSource(String path) throws IllegalArgumentException, IllegalStateException, IOException { + Log.d(SBMP_TAG, "setDataSource(path)"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface == null) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + else { + try { + pmInterface.setDataSourceString( + ServiceBackedMediaPlayer.this.sessionId, + path); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + } + + /** + * Sets whether to use speed adjustment or not. Speed adjustment on is + * more computation-intensive than with it off. + * @param enableSpeedAdjustment Whether speed adjustment should be supported. + */ + @Override + public void setEnableSpeedAdjustment(boolean enableSpeedAdjustment) { + // TODO: This has no business being here, I think + owningMediaPlayer.lock.lock(); + Log.d(SBMP_TAG, "setEnableSpeedAdjustment(enableSpeedAdjustment)"); + try { + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the Service isn't connected + try { + pmInterface.setEnableSpeedAdjustment( + ServiceBackedMediaPlayer.this.sessionId, + enableSpeedAdjustment); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + + + /** + * Functions identically to android.media.MediaPlayer.setLooping(boolean loop) + * Sets the track to loop infinitely if loop is true, play once if loop is false + */ + @Override + public void setLooping(boolean loop) { + Log.d(SBMP_TAG, "setLooping(" + loop + ")"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.setLooping(ServiceBackedMediaPlayer.this.sessionId, loop); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Sets the number of steps (in a musical scale) by which playback is + * currently shifted. When greater than zero, pitch is shifted up. + * When less than zero, pitch is shifted down. + * + * @param pitchSteps The number of steps by which to shift playback + */ + @Override + public void setPitchStepsAdjustment(float pitchSteps) { + Log.d(SBMP_TAG, "setPitchStepsAdjustment(" + pitchSteps + ")"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the Service isn't connected + try { + pmInterface.setPitchStepsAdjustment( + ServiceBackedMediaPlayer.this.sessionId, + pitchSteps); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + } + + /** + * Sets the percentage by which pitch is currently shifted. When + * greater than zero, pitch is shifted up. When less than zero, pitch + * is shifted down + * @param f The percentage to shift pitch + */ + @Override + public void setPlaybackPitch(float f) { + Log.d(SBMP_TAG, "setPlaybackPitch(" + f + ")"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the Service isn't connected + try { + pmInterface.setPlaybackPitch( + ServiceBackedMediaPlayer.this.sessionId, + f); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + } + + /** + * Set playback speed. 1.0 is normal speed, 2.0 is double speed, and so + * on. Speed should never be set to 0 or below. + * @param f The speed multiplier to use for further playback + */ + @Override + public void setPlaybackSpeed(float f) { + Log.d(SBMP_TAG, "setPlaybackSpeed(" + f + ")"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + if (pmInterface != null) { + // Can't set speed if the Service isn't connected + try { + pmInterface.setPlaybackSpeed( + ServiceBackedMediaPlayer.this.sessionId, + f); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + } + + @Override + public void setSpeedAdjustmentAlgorithm(int algorithm) { + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.setSpeedAdjustmentAlgorithm( + ServiceBackedMediaPlayer.this.sessionId, + algorithm); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setVolume(float leftVolume, float rightVolume) + * Sets the stereo volume + */ + @Override + public void setVolume(float leftVolume, float rightVolume) { + Log.d(SBMP_TAG, "setVolume(" + leftVolume + ", " + rightVolume + ")"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.setVolume( + ServiceBackedMediaPlayer.this.sessionId, + leftVolume, + rightVolume); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.setWakeMode(Context context, int mode) + * Acquires a wake lock in the context given. You must request the appropriate permissions + * in your AndroidManifest.xml file. + */ + @Override + // This does not just call .setWakeMode() in the Service because doing so + // would add a permission requirement to the Service. Do it here, and it's + // the client app's responsibility to request that permission + public void setWakeMode(Context context, int mode) { + Log.d(SBMP_TAG, "setWakeMode(context, " + mode + ")"); + if ((this.mWakeLock != null) + && (this.mWakeLock.isHeld())) { + this.mWakeLock.release(); + } + if (mode != 0) { + if (this.mWakeLock == null) { + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + // Since mode can't be changed on the fly, we have to allocate a new one + this.mWakeLock = pm.newWakeLock(mode, this.getClass().getName()); + } + + this.mWakeLock.acquire(); + } + } + + private IOnBufferingUpdateListenerCallback_0_8.Stub mOnBufferingUpdateCallback = null; + private void setOnBufferingUpdateCallback(IPlayMedia_0_8 iface) { + try { + if (this.mOnBufferingUpdateCallback == null) { + mOnBufferingUpdateCallback = new IOnBufferingUpdateListenerCallback_0_8.Stub() { + public void onBufferingUpdate(int percent) + throws RemoteException { + owningMediaPlayer.lock.lock(); + try { + if ((owningMediaPlayer.onBufferingUpdateListener != null) + && (owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this)) { + owningMediaPlayer.onBufferingUpdateListener.onBufferingUpdate(owningMediaPlayer, percent); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + }; + } + iface.registerOnBufferingUpdateCallback( + ServiceBackedMediaPlayer.this.sessionId, + mOnBufferingUpdateCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private IOnCompletionListenerCallback_0_8.Stub mOnCompletionCallback = null; + private void setOnCompletionCallback(IPlayMedia_0_8 iface) { + try { + if (this.mOnCompletionCallback == null) { + this.mOnCompletionCallback = new IOnCompletionListenerCallback_0_8.Stub() { + public void onCompletion() throws RemoteException { + owningMediaPlayer.lock.lock(); + Log.d(SBMP_TAG, "onCompletionListener being called"); + try { + if (owningMediaPlayer.onCompletionListener != null) { + owningMediaPlayer.onCompletionListener.onCompletion(owningMediaPlayer); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + }; + } + iface.registerOnCompletionCallback( + ServiceBackedMediaPlayer.this.sessionId, + this.mOnCompletionCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private IOnErrorListenerCallback_0_8.Stub mOnErrorCallback = null; + private void setOnErrorCallback(IPlayMedia_0_8 iface) { + try { + if (this.mOnErrorCallback == null) { + this.mOnErrorCallback = new IOnErrorListenerCallback_0_8.Stub() { + public boolean onError(int what, int extra) throws RemoteException { + owningMediaPlayer.lock.lock(); + try { + if (owningMediaPlayer.onErrorListener != null) { + return owningMediaPlayer.onErrorListener.onError(owningMediaPlayer, what, extra); + } + return false; + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + }; + } + iface.registerOnErrorCallback( + ServiceBackedMediaPlayer.this.sessionId, + this.mOnErrorCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private IOnInfoListenerCallback_0_8.Stub mOnInfoCallback = null; + private void setOnInfoCallback(IPlayMedia_0_8 iface) { + try { + if (this.mOnInfoCallback == null) { + this.mOnInfoCallback = new IOnInfoListenerCallback_0_8.Stub() { + public boolean onInfo(int what, int extra) throws RemoteException { + owningMediaPlayer.lock.lock(); + try { + if ((owningMediaPlayer.onInfoListener != null) + && (owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this)) { + return owningMediaPlayer.onInfoListener.onInfo(owningMediaPlayer, what, extra); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + return false; + } + }; + } + iface.registerOnInfoCallback( + ServiceBackedMediaPlayer.this.sessionId, + this.mOnInfoCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.Stub mOnPitchAdjustmentAvailableChangedCallback = null; + private void setOnPitchAdjustmentAvailableChangedListener(IPlayMedia_0_8 iface) { + try { + if (this.mOnPitchAdjustmentAvailableChangedCallback == null) { + this.mOnPitchAdjustmentAvailableChangedCallback = new IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.Stub() { + public void onPitchAdjustmentAvailableChanged( + boolean pitchAdjustmentAvailable) + throws RemoteException { + owningMediaPlayer.lock.lock(); + try { + if (owningMediaPlayer.onPitchAdjustmentAvailableChangedListener != null) { + owningMediaPlayer.onPitchAdjustmentAvailableChangedListener.onPitchAdjustmentAvailableChanged(owningMediaPlayer, pitchAdjustmentAvailable); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + }; + } + iface.registerOnPitchAdjustmentAvailableChangedCallback( + ServiceBackedMediaPlayer.this.sessionId, + this.mOnPitchAdjustmentAvailableChangedCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private IOnPreparedListenerCallback_0_8.Stub mOnPreparedCallback = null; + private void setOnPreparedCallback(IPlayMedia_0_8 iface) { + try { + if (this.mOnPreparedCallback == null) { + this.mOnPreparedCallback = new IOnPreparedListenerCallback_0_8.Stub() { + public void onPrepared() throws RemoteException { + owningMediaPlayer.lock.lock(); + Log.d(SBMP_TAG, "setOnPreparedCallback.mOnPreparedCallback.onPrepared 1050"); + try { + Log.d(SBMP_TAG, "owningMediaPlayer.onPreparedListener is " + ((owningMediaPlayer.onPreparedListener == null) ? "null" : "non-null")); + Log.d(SBMP_TAG, "owningMediaPlayer.mpi is " + ((owningMediaPlayer.mpi == ServiceBackedMediaPlayer.this) ? "this" : "not this")); + ServiceBackedMediaPlayer.this.lockMuteOnPreparedCount.lock(); + try { + if (ServiceBackedMediaPlayer.this.muteOnPreparedCount > 0) { + ServiceBackedMediaPlayer.this.muteOnPreparedCount--; + } + else { + ServiceBackedMediaPlayer.this.muteOnPreparedCount = 0; + if (ServiceBackedMediaPlayer.this.owningMediaPlayer.onPreparedListener != null) { + owningMediaPlayer.onPreparedListener.onPrepared(owningMediaPlayer); + } + } + } + finally { + ServiceBackedMediaPlayer.this.lockMuteOnPreparedCount.unlock(); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + }; + } + iface.registerOnPreparedCallback( + ServiceBackedMediaPlayer.this.sessionId, + this.mOnPreparedCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private IOnSeekCompleteListenerCallback_0_8.Stub mOnSeekCompleteCallback = null; + private void setOnSeekCompleteCallback(IPlayMedia_0_8 iface) { + try { + if (this.mOnSeekCompleteCallback == null) { + this.mOnSeekCompleteCallback = new IOnSeekCompleteListenerCallback_0_8.Stub() { + public void onSeekComplete() throws RemoteException { + Log.d(SBMP_TAG, "onSeekComplete() 941"); + owningMediaPlayer.lock.lock(); + try { + if (ServiceBackedMediaPlayer.this.muteOnSeekCount > 0) { + Log.d(SBMP_TAG, "The next " + ServiceBackedMediaPlayer.this.muteOnSeekCount + " seek events are muted (counting this one)"); + ServiceBackedMediaPlayer.this.muteOnSeekCount--; + } + else { + ServiceBackedMediaPlayer.this.muteOnSeekCount = 0; + Log.d(SBMP_TAG, "Attempting to invoke next seek event"); + if (ServiceBackedMediaPlayer.this.owningMediaPlayer.onSeekCompleteListener != null) { + Log.d(SBMP_TAG, "Invoking onSeekComplete"); + owningMediaPlayer.onSeekCompleteListener.onSeekComplete(owningMediaPlayer); + } + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + }; + } + iface.registerOnSeekCompleteCallback( + ServiceBackedMediaPlayer.this.sessionId, + this.mOnSeekCompleteCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + private IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.Stub mOnSpeedAdjustmentAvailableChangedCallback = null; + private void setOnSpeedAdjustmentAvailableChangedCallback(IPlayMedia_0_8 iface) { + try { + Log.d(SBMP_TAG, "Setting the service of on speed adjustment available changed"); + if (this.mOnSpeedAdjustmentAvailableChangedCallback == null) { + this.mOnSpeedAdjustmentAvailableChangedCallback = new IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.Stub() { + public void onSpeedAdjustmentAvailableChanged( + boolean speedAdjustmentAvailable) + throws RemoteException { + owningMediaPlayer.lock.lock(); + try { + if (owningMediaPlayer.onSpeedAdjustmentAvailableChangedListener != null) { + owningMediaPlayer.onSpeedAdjustmentAvailableChangedListener.onSpeedAdjustmentAvailableChanged(owningMediaPlayer, speedAdjustmentAvailable); + } + } + finally { + owningMediaPlayer.lock.unlock(); + } + } + }; + } + iface.registerOnSpeedAdjustmentAvailableChangedCallback( + ServiceBackedMediaPlayer.this.sessionId, + this.mOnSpeedAdjustmentAvailableChangedCallback); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.start() + * Starts a track playing + */ + @Override + public void start() { + Log.d(SBMP_TAG, "start()"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.start(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + + /** + * Functions identically to android.media.MediaPlayer.stop() + * Stops a track playing and resets its position to the start. + */ + @Override + public void stop() { + Log.d(SBMP_TAG, "stop()"); + if (pmInterface == null) { + if (!ConnectPlayMediaService()) { + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } + try { + pmInterface.stop(ServiceBackedMediaPlayer.this.sessionId); + } catch (RemoteException e) { + e.printStackTrace(); + ServiceBackedMediaPlayer.this.error(MediaPlayer.MEDIA_ERROR_UNKNOWN, 0); + } + } +}
\ No newline at end of file diff --git a/src/com/aocate/media/SpeedAdjustmentAlgorithm.java b/src/com/aocate/media/SpeedAdjustmentAlgorithm.java new file mode 100644 index 000000000..d337a0452 --- /dev/null +++ b/src/com/aocate/media/SpeedAdjustmentAlgorithm.java @@ -0,0 +1,31 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.media; + +public class SpeedAdjustmentAlgorithm { + /** + * Use this to use the user-specified algorithm + */ + public static int DEFAULT = 0; + + /** + * Better for voice audio + */ + public static int SONIC = 1; + /** + * Better for music audio + */ + public static int WSOLA = 2; +} diff --git a/src/com/aocate/presto/service/IDeathCallback_0_8.aidl b/src/com/aocate/presto/service/IDeathCallback_0_8.aidl new file mode 100644 index 000000000..6bdc76801 --- /dev/null +++ b/src/com/aocate/presto/service/IDeathCallback_0_8.aidl @@ -0,0 +1,18 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +oneway interface IDeathCallback_0_8 { +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl new file mode 100644 index 000000000..7357e402e --- /dev/null +++ b/src/com/aocate/presto/service/IOnBufferingUpdateListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnBufferingUpdateListenerCallback_0_8 { + void onBufferingUpdate(int percent); +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl new file mode 100644 index 000000000..d5edea729 --- /dev/null +++ b/src/com/aocate/presto/service/IOnCompletionListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnCompletionListenerCallback_0_8 { + void onCompletion(); +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl new file mode 100644 index 000000000..2c4f2df3e --- /dev/null +++ b/src/com/aocate/presto/service/IOnErrorListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnErrorListenerCallback_0_8 { + boolean onError(int what, int extra); +} diff --git a/src/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl new file mode 100644 index 000000000..9dbd1d260 --- /dev/null +++ b/src/com/aocate/presto/service/IOnInfoListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnInfoListenerCallback_0_8 { + boolean onInfo(int what, int extra); +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl new file mode 100644 index 000000000..41223a97b --- /dev/null +++ b/src/com/aocate/presto/service/IOnPitchAdjustmentAvailableChangedListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 { + void onPitchAdjustmentAvailableChanged(boolean pitchAdjustmentAvailable); +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl new file mode 100644 index 000000000..7be8f1237 --- /dev/null +++ b/src/com/aocate/presto/service/IOnPreparedListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnPreparedListenerCallback_0_8 { + void onPrepared(); +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl new file mode 100644 index 000000000..5bdda98b6 --- /dev/null +++ b/src/com/aocate/presto/service/IOnSeekCompleteListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnSeekCompleteListenerCallback_0_8 { + void onSeekComplete(); +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl b/src/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl new file mode 100644 index 000000000..a69c1cf34 --- /dev/null +++ b/src/com/aocate/presto/service/IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8.aidl @@ -0,0 +1,19 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +interface IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 { + void onSpeedAdjustmentAvailableChanged(boolean speedAdjustmentAvailable); +}
\ No newline at end of file diff --git a/src/com/aocate/presto/service/IPlayMedia_0_8.aidl b/src/com/aocate/presto/service/IPlayMedia_0_8.aidl new file mode 100644 index 000000000..12a6047de --- /dev/null +++ b/src/com/aocate/presto/service/IPlayMedia_0_8.aidl @@ -0,0 +1,75 @@ +// Copyright 2011, Aocate, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.aocate.presto.service; + +import com.aocate.presto.service.IDeathCallback_0_8; +import com.aocate.presto.service.IOnBufferingUpdateListenerCallback_0_8; +import com.aocate.presto.service.IOnCompletionListenerCallback_0_8; +import com.aocate.presto.service.IOnErrorListenerCallback_0_8; +import com.aocate.presto.service.IOnPitchAdjustmentAvailableChangedListenerCallback_0_8; +import com.aocate.presto.service.IOnPreparedListenerCallback_0_8; +import com.aocate.presto.service.IOnSeekCompleteListenerCallback_0_8; +import com.aocate.presto.service.IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8; +import com.aocate.presto.service.IOnInfoListenerCallback_0_8; + +interface IPlayMedia_0_8 { + boolean canSetPitch(long sessionId); + boolean canSetSpeed(long sessionId); + float getCurrentPitchStepsAdjustment(long sessionId); + int getCurrentPosition(long sessionId); + float getCurrentSpeedMultiplier(long sessionId); + int getDuration(long sessionId); + float getMaxSpeedMultiplier(long sessionId); + float getMinSpeedMultiplier(long sessionId); + int getVersionCode(); + String getVersionName(); + boolean isLooping(long sessionId); + boolean isPlaying(long sessionId); + void pause(long sessionId); + void prepare(long sessionId); + void prepareAsync(long sessionId); + void registerOnBufferingUpdateCallback(long sessionId, IOnBufferingUpdateListenerCallback_0_8 cb); + void registerOnCompletionCallback(long sessionId, IOnCompletionListenerCallback_0_8 cb); + void registerOnErrorCallback(long sessionId, IOnErrorListenerCallback_0_8 cb); + void registerOnInfoCallback(long sessionId, IOnInfoListenerCallback_0_8 cb); + void registerOnPitchAdjustmentAvailableChangedCallback(long sessionId, IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 cb); + void registerOnPreparedCallback(long sessionId, IOnPreparedListenerCallback_0_8 cb); + void registerOnSeekCompleteCallback(long sessionId, IOnSeekCompleteListenerCallback_0_8 cb); + void registerOnSpeedAdjustmentAvailableChangedCallback(long sessionId, IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 cb); + void release(long sessionId); + void reset(long sessionId); + void seekTo(long sessionId, int msec); + void setAudioStreamType(long sessionId, int streamtype); + void setDataSourceString(long sessionId, String path); + void setDataSourceUri(long sessionId, in Uri uri); + void setEnableSpeedAdjustment(long sessionId, boolean enableSpeedAdjustment); + void setLooping(long sessionId, boolean looping); + void setPitchStepsAdjustment(long sessionId, float pitchSteps); + void setPlaybackPitch(long sessionId, float f); + void setPlaybackSpeed(long sessionId, float f); + void setSpeedAdjustmentAlgorithm(long sessionId, int algorithm); + void setVolume(long sessionId, float left, float right); + void start(long sessionId); + long startSession(IDeathCallback_0_8 cb); + void stop(long sessionId); + void unregisterOnBufferingUpdateCallback(long sessionId, IOnBufferingUpdateListenerCallback_0_8 cb); + void unregisterOnCompletionCallback(long sessionId, IOnCompletionListenerCallback_0_8 cb); + void unregisterOnErrorCallback(long sessionId, IOnErrorListenerCallback_0_8 cb); + void unregisterOnInfoCallback(long sessionId, IOnInfoListenerCallback_0_8 cb); + void unregisterOnPitchAdjustmentAvailableChangedCallback(long sessionId, IOnPitchAdjustmentAvailableChangedListenerCallback_0_8 cb); + void unregisterOnPreparedCallback(long sessionId, IOnPreparedListenerCallback_0_8 cb); + void unregisterOnSeekCompleteCallback(long sessionId, IOnSeekCompleteListenerCallback_0_8 cb); + void unregisterOnSpeedAdjustmentAvailableChangedCallback(long sessionId, IOnSpeedAdjustmentAvailableChangedListenerCallback_0_8 cb); +}
\ No newline at end of file diff --git a/src/de/danoeh/antennapod/AppConfig.java b/src/de/danoeh/antennapod/AppConfig.java index d1b403722..98a231330 100644 --- a/src/de/danoeh/antennapod/AppConfig.java +++ b/src/de/danoeh/antennapod/AppConfig.java @@ -1,8 +1,6 @@ package de.danoeh.antennapod; public final class AppConfig { - /** Should be used for debug logging. */ - public final static boolean DEBUG = true; /** Should be used when setting User-Agent header for HTTP-requests. */ - public final static String USER_AGENT = "AntennaPod/0.9.8.2"; + public final static String USER_AGENT = "AntennaPod/0.9.8.3"; } diff --git a/src/de/danoeh/antennapod/PodcastApp.java b/src/de/danoeh/antennapod/PodcastApp.java index 2141f71e8..4c4766327 100644 --- a/src/de/danoeh/antennapod/PodcastApp.java +++ b/src/de/danoeh/antennapod/PodcastApp.java @@ -7,6 +7,7 @@ import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.preferences.PlaybackPreferences; import de.danoeh.antennapod.preferences.UserPreferences; +import de.danoeh.antennapod.spa.SPAUtil; /** Main application class. */ public class PodcastApp extends Application { @@ -31,6 +32,8 @@ public class PodcastApp extends Application { UserPreferences.createInstance(this); PlaybackPreferences.createInstance(this); EventDistributor.getInstance(); + + SPAUtil.sendSPAppsQueryFeedsIntent(this); } @Override diff --git a/src/de/danoeh/antennapod/activity/AboutActivity.java b/src/de/danoeh/antennapod/activity/AboutActivity.java index 27fdbe241..cf7de1709 100644 --- a/src/de/danoeh/antennapod/activity/AboutActivity.java +++ b/src/de/danoeh/antennapod/activity/AboutActivity.java @@ -4,8 +4,6 @@ import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.webkit.WebView; import android.webkit.WebViewClient; - - import de.danoeh.antennapod.R; /** Displays the 'about' screen */ diff --git a/src/de/danoeh/antennapod/activity/AddFeedActivity.java b/src/de/danoeh/antennapod/activity/AddFeedActivity.java index 82e03f122..a77689ddb 100644 --- a/src/de/danoeh/antennapod/activity/AddFeedActivity.java +++ b/src/de/danoeh/antennapod/activity/AddFeedActivity.java @@ -1,84 +1,68 @@ package de.danoeh.antennapod.activity; -import java.util.Date; - -import android.support.v4.app.NavUtils; -import android.support.v7.app.ActionBarActivity; -import android.view.Menu; -import android.view.MenuItem; -import de.danoeh.antennapod.activity.gpoddernet.GpodnetMainActivity; -import org.apache.commons.lang3.StringUtils; - -import android.app.AlertDialog; import android.app.ProgressDialog; -import android.content.DialogInterface; import android.content.Intent; import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.feed.Feed; +import de.danoeh.antennapod.activity.gpoddernet.GpodnetMainActivity; import de.danoeh.antennapod.preferences.UserPreferences; -import de.danoeh.antennapod.storage.DownloadRequestException; -import de.danoeh.antennapod.storage.DownloadRequester; -import de.danoeh.antennapod.util.ConnectionTester; -import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.StorageUtils; -import de.danoeh.antennapod.util.URLChecker; +import org.apache.commons.lang3.StringUtils; -/** Activity for adding a Feed */ +/** + * Activity for adding a Feed + */ public class AddFeedActivity extends ActionBarActivity { - private static final String TAG = "AddFeedActivity"; + private static final String TAG = "AddFeedActivity"; - private DownloadRequester requester; - - private EditText etxtFeedurl; - private Button butBrowseMiroGuide; + private EditText etxtFeedurl; + private Button butBrowseMiroGuide; private Button butBrowserGpoddernet; - private Button butOpmlImport; - private Button butConfirm; - private Button butCancel; - - private ProgressDialog progDialog; - - @Override - protected void onCreate(Bundle savedInstanceState) { - if (AppConfig.DEBUG) - Log.d(TAG, "Was started with Intent " + getIntent().getAction() - + " and Data " + getIntent().getDataString()); - setTheme(UserPreferences.getTheme()); - super.onCreate(savedInstanceState); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - StorageUtils.checkStorageAvailability(this); - setContentView(R.layout.addfeed); - - requester = DownloadRequester.getInstance(); - progDialog = new ProgressDialog(this); - - etxtFeedurl = (EditText) findViewById(R.id.etxtFeedurl); - if (StringUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) { - etxtFeedurl.setText(getIntent().getDataString()); - } - - butBrowseMiroGuide = (Button) findViewById(R.id.butBrowseMiroguide); + private Button butOpmlImport; + private Button butConfirm; + + private ProgressDialog progDialog; + + @Override + protected void onCreate(Bundle savedInstanceState) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Was started with Intent " + getIntent().getAction() + + " and Data " + getIntent().getDataString()); + setTheme(UserPreferences.getTheme()); + super.onCreate(savedInstanceState); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + StorageUtils.checkStorageAvailability(this); + setContentView(R.layout.addfeed); + + progDialog = new ProgressDialog(this); + + etxtFeedurl = (EditText) findViewById(R.id.etxtFeedurl); + if (StringUtils.equals(getIntent().getAction(), Intent.ACTION_VIEW)) { + etxtFeedurl.setText(getIntent().getDataString()); + } + + butBrowseMiroGuide = (Button) findViewById(R.id.butBrowseMiroguide); butBrowserGpoddernet = (Button) findViewById(R.id.butBrowseGpoddernet); - butOpmlImport = (Button) findViewById(R.id.butOpmlImport); - butConfirm = (Button) findViewById(R.id.butConfirm); - butCancel = (Button) findViewById(R.id.butCancel); - - butBrowseMiroGuide.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - startActivity(new Intent(AddFeedActivity.this, - MiroGuideMainActivity.class)); - } - }); + butOpmlImport = (Button) findViewById(R.id.butOpmlImport); + butConfirm = (Button) findViewById(R.id.butConfirm); + + butBrowseMiroGuide.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + startActivity(new Intent(AddFeedActivity.this, + MiroGuideMainActivity.class)); + } + }); butBrowserGpoddernet.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { @@ -87,141 +71,74 @@ public class AddFeedActivity extends ActionBarActivity { } }); - butOpmlImport.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - startActivity(new Intent(AddFeedActivity.this, - OpmlImportFromPathActivity.class)); - } - }); - - butConfirm.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - addNewFeed(); - } - }); - - butCancel.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setResult(RESULT_CANCELED); - finish(); - } - }); - } - - @Override - protected void onResume() { - super.onResume(); - StorageUtils.checkStorageAvailability(this); - Intent intent = getIntent(); - if (intent.getAction() != null - && intent.getAction().equals(Intent.ACTION_SEND)) { - if (AppConfig.DEBUG) - Log.d(TAG, "Resuming with ACTION_SEND intent"); - String text = intent.getStringExtra(Intent.EXTRA_TEXT); - if (text != null) { - etxtFeedurl.setText(text); - } else { - if (AppConfig.DEBUG) - Log.d(TAG, "No text was sent"); - } - } - - } - - @Override - protected void onStop() { - super.onStop(); - if (AppConfig.DEBUG) - Log.d(TAG, "Stopping Activity"); - } - - @Override - protected void onPause() { - super.onPause(); - } - - /** Read the url text field and start downloading a new feed. */ - private void addNewFeed() { - String url = etxtFeedurl.getText().toString(); - url = URLChecker.prepareURL(url); - - if (url != null) { - final Feed feed = new Feed(url, new Date()); - final ConnectionTester conTester = new ConnectionTester(url, - new ConnectionTester.Callback() { - - @Override - public void onConnectionSuccessful() { - try { - requester.downloadFeed(AddFeedActivity.this, - feed); - if (progDialog.isShowing()) { - progDialog.dismiss(); - finish(); - } - } catch (DownloadRequestException e) { - e.printStackTrace(); - onConnectionFailure(DownloadError.ERROR_REQUEST_ERROR); - } - - } - - @Override - public void onConnectionFailure(DownloadError reason) { - handleDownloadError(reason); - } - }); - observeDownload(feed); - new Thread(conTester).start(); - - } - } - - /** Start listening for any intents send by the DownloadService. */ - private void observeDownload(Feed feed) { - progDialog.show(); - progDialog.setMessage(getString(R.string.loading_label)); - } - - private void handleDownloadError(DownloadError reason) { - final AlertDialog errorDialog = new AlertDialog.Builder(this).create(); - errorDialog.setTitle(R.string.error_label); - errorDialog.setMessage(getString(R.string.error_msg_prefix) + " " - + reason.getErrorString(this)); - errorDialog.setButton(getString(android.R.string.ok), - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - errorDialog.dismiss(); - } - }); - if (progDialog.isShowing()) { - progDialog.dismiss(); - } - errorDialog.show(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - return true; - } + butOpmlImport.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + startActivity(new Intent(AddFeedActivity.this, + OpmlImportFromPathActivity.class)); + } + }); + butConfirm.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(AddFeedActivity.this, DefaultOnlineFeedViewActivity.class); + intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, etxtFeedurl.getText().toString()); + intent.putExtra(OnlineFeedViewActivity.ARG_TITLE, getSupportActionBar().getTitle()); + startActivity(intent); + } + }); + } + + @Override + protected void onResume() { + super.onResume(); + StorageUtils.checkStorageAvailability(this); + Intent intent = getIntent(); + if (intent.getAction() != null + && intent.getAction().equals(Intent.ACTION_SEND)) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Resuming with ACTION_SEND intent"); + String text = intent.getStringExtra(Intent.EXTRA_TEXT); + if (text != null) { + etxtFeedurl.setText(text); + } else { + if (BuildConfig.DEBUG) + Log.d(TAG, "No text was sent"); + } + } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case android.R.id.home: - finish(); - return true; - default: - return false; - } - } + } + + @Override + protected void onStop() { + super.onStop(); + if (BuildConfig.DEBUG) + Log.d(TAG, "Stopping Activity"); + } + + @Override + protected void onPause() { + super.onPause(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + super.onCreateOptionsMenu(menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + default: + return false; + } + } } diff --git a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java index a55f8120e..de989fa46 100644 --- a/src/de/danoeh/antennapod/activity/AudioplayerActivity.java +++ b/src/de/danoeh/antennapod/activity/AudioplayerActivity.java @@ -15,7 +15,7 @@ import android.view.View.OnLongClickListener; import android.view.Window; import android.widget.*; import android.widget.ImageView.ScaleType; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.ChapterListAdapter; import de.danoeh.antennapod.asynctask.ImageLoader; @@ -67,29 +67,29 @@ public class AudioplayerActivity extends MediaplayerActivity { FragmentTransaction fT = getSupportFragmentManager().beginTransaction(); if (coverFragment != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Removing cover fragment"); fT.remove(coverFragment); } if (descriptionFragment != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Removing description fragment"); fT.remove(descriptionFragment); } if (chapterFragment != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Removing chapter fragment"); fT.remove(chapterFragment); } if (currentlyShownFragment != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Removing currently shown fragment"); fT.remove(currentlyShownFragment); } for (int i = 0; i < detachedFragments.length; i++) { Fragment f = detachedFragments[i]; if (f != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Removing detached fragment"); fT.remove(f); } @@ -106,7 +106,7 @@ public class AudioplayerActivity extends MediaplayerActivity { @Override protected void onStop() { super.onStop(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "onStop"); } @@ -120,7 +120,7 @@ public class AudioplayerActivity extends MediaplayerActivity { } private void savePreferences() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Saving preferences"); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); @@ -147,7 +147,7 @@ public class AudioplayerActivity extends MediaplayerActivity { @Override protected void onSaveInstanceState(Bundle outState) { // super.onSaveInstanceState(outState); would cause crash - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "onSaveInstanceState"); } @@ -171,7 +171,7 @@ public class AudioplayerActivity extends MediaplayerActivity { * @return true if restoreFromPrefernces changed the activity's state */ private boolean restoreFromPreferences() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Restoring instance state"); SharedPreferences prefs = getSharedPreferences(PREFS, MODE_PRIVATE); int savedPosition = prefs.getInt(PREF_KEY_SELECTED_FRAGMENT_POSITION, @@ -186,11 +186,11 @@ public class AudioplayerActivity extends MediaplayerActivity { switchToFragment(savedPosition); return true; } else if (controller == null || controller.getMedia() == null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Couldn't restore from preferences: controller or media was null"); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Couldn't restore from preferences: savedPosition was -1 or saved identifier and playable identifier didn't match.\nsavedPosition: " + savedPosition + ", id: " + playableId); @@ -205,7 +205,7 @@ public class AudioplayerActivity extends MediaplayerActivity { if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_VIEW)) { Intent intent = getIntent(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath()); ExternalMedia media = new ExternalMedia(intent.getData().getPath(), @@ -233,7 +233,7 @@ public class AudioplayerActivity extends MediaplayerActivity { @Override protected void onAwaitingVideoSurface() { - if (AppConfig.DEBUG) Log.d(TAG, "onAwaitingVideoSurface was called in audio player -> switching to video player"); + if (BuildConfig.DEBUG) Log.d(TAG, "onAwaitingVideoSurface was called in audio player -> switching to video player"); startActivity(new Intent(this, VideoplayerActivity.class)); } @@ -255,7 +255,7 @@ public class AudioplayerActivity extends MediaplayerActivity { * @param pos Must be POS_COVER, POS_DESCR, or POS_CHAPTERS */ private void switchToFragment(int pos) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Switching contentView to position " + pos); if (currentlyShownPosition != pos && controller != null) { Playable media = controller.getMedia(); @@ -305,7 +305,7 @@ public class AudioplayerActivity extends MediaplayerActivity { if (currentlyShownFragment != null) { currentlyShownPosition = pos; if (detachedFragments[pos] != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Reattaching fragment at position " + pos); ft.attach(detachedFragments[pos]); @@ -330,6 +330,10 @@ public class AudioplayerActivity extends MediaplayerActivity { R.attr.navigation_shownotes, R.attr.navigation_chapters}); final Playable media = controller.getMedia(); if (butNavLeft != null && butNavRight != null && media != null) { + + butNavRight.setTag(R.id.imageloader_key, null); + butNavLeft.setTag(R.id.imageloader_key, null); + switch (currentlyShownPosition) { case POS_COVER: butNavLeft.setScaleType(ScaleType.CENTER); @@ -519,7 +523,7 @@ public class AudioplayerActivity extends MediaplayerActivity { @Override protected void onReloadNotification(int notificationCode) { if (notificationCode == PlaybackService.EXTRA_CODE_VIDEO) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "ReloadNotification received, switching to Videoplayer now"); finish(); diff --git a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java index bb56b1d12..5709fc958 100644 --- a/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/DefaultOnlineFeedViewActivity.java @@ -3,7 +3,6 @@ package de.danoeh.antennapod.activity; import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; -import android.support.v4.app.NavUtils; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; @@ -90,10 +89,11 @@ public class DefaultOnlineFeedViewActivity extends OnlineFeedViewActivity { @Override public void onClick(View v) { try { + Feed f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle()); + f.setPreferences(feed.getPreferences()); DownloadRequester.getInstance().downloadFeed( DefaultOnlineFeedViewActivity.this, - new Feed(feed.getDownload_url(), new Date(), feed - .getTitle())); + f); } catch (DownloadRequestException e) { e.printStackTrace(); DownloadRequestErrorDialogCreator.newRequestErrorDialog(DefaultOnlineFeedViewActivity.this, diff --git a/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java b/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java index c734b2768..06a11c775 100644 --- a/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java +++ b/src/de/danoeh/antennapod/activity/DirectoryChooserActivity.java @@ -1,10 +1,5 @@ package de.danoeh.antennapod.activity; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; - import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; @@ -20,19 +15,17 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; -import android.widget.AdapterView; +import android.widget.*; import android.widget.AdapterView.OnItemClickListener; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import android.widget.Toast; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.preferences.UserPreferences; +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + /** * Let's the user choose a directory on the storage device. The selected folder * will be sent back to the starting activity as an activity result. @@ -127,7 +120,7 @@ public class DirectoryChooserActivity extends ActionBarActivity { @Override public void onItemClick(AdapterView<?> adapter, View view, int position, long id) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Selected index: " + position); if (filesInDir != null && position >= 0 && position < filesInDir.length) { @@ -160,7 +153,7 @@ public class DirectoryChooserActivity extends ActionBarActivity { * selected folder can also be null. */ private void returnSelectedFolder() { - if (selectedDir != null && AppConfig.DEBUG) + if (selectedDir != null && BuildConfig.DEBUG) Log.d(TAG, "Returning " + selectedDir.getAbsolutePath() + " as result"); Intent resultData = new Intent(); @@ -222,19 +215,19 @@ public class DirectoryChooserActivity extends ActionBarActivity { listDirectoriesAdapter.notifyDataSetChanged(); fileObserver = createFileObserver(dir.getAbsolutePath()); fileObserver.startWatching(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Changed directory to " + dir.getAbsolutePath()); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Could not change folder: contents of dir were null"); } } else { if (dir == null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Could not change folder: dir was null"); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Could not change folder: dir is no directory"); } } @@ -266,7 +259,7 @@ public class DirectoryChooserActivity extends ActionBarActivity { @Override public void onEvent(int event, String path) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "FileObserver received event " + event); runOnUiThread(new Runnable() { diff --git a/src/de/danoeh/antennapod/activity/DownloadActivity.java b/src/de/danoeh/antennapod/activity/DownloadActivity.java index f5986baf5..996929cdb 100644 --- a/src/de/danoeh/antennapod/activity/DownloadActivity.java +++ b/src/de/danoeh/antennapod/activity/DownloadActivity.java @@ -14,7 +14,7 @@ import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ListView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.DownloadlistAdapter; import de.danoeh.antennapod.asynctask.DownloadObserver; @@ -53,7 +53,7 @@ public class DownloadActivity extends ActionBarActivity implements listview = (ListView) findViewById(R.id.listview); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating Activity"); requester = DownloadRequester.getInstance(); getSupportActionBar().setDisplayHomeAsUpEnabled(true); @@ -78,7 +78,7 @@ public class DownloadActivity extends ActionBarActivity implements @Override protected void onStop() { super.onStop(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Stopping Activity"); } diff --git a/src/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java b/src/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java new file mode 100644 index 000000000..4b8420e45 --- /dev/null +++ b/src/de/danoeh/antennapod/activity/DownloadAuthenticationActivity.java @@ -0,0 +1,106 @@ +package de.danoeh.antennapod.activity; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import de.danoeh.antennapod.BuildConfig; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.preferences.UserPreferences; +import de.danoeh.antennapod.service.download.DownloadRequest; +import de.danoeh.antennapod.storage.DownloadRequester; + +/** + * Shows a username and a password text field. + * The activity MUST be started with the ARG_DOWNlOAD_REQUEST argument set to a non-null value. + * Other arguments are optional. + * The activity's result will be the same DownloadRequest with the entered username and password. + */ +public class DownloadAuthenticationActivity extends ActionBarActivity { + private static final String TAG = "DownloadAuthenticationActivity"; + + /** + * The download request object that contains information about the resource that requires a username and a password + */ + public static final String ARG_DOWNLOAD_REQUEST = "request"; + /** + * True if the request should be sent to the DownloadRequester when this activity is finished, false otherwise. + * The default value is false. + */ + public static final String ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL = "send_to_downloadrequester"; + + public static final String RESULT_REQUEST = "request"; + + private EditText etxtUsername; + private EditText etxtPassword; + private Button butConfirm; + private Button butCancel; + private TextView txtvDescription; + + private DownloadRequest request; + private boolean sendToDownloadRequester; + + @Override + protected void onCreate(Bundle savedInstanceState) { + setTheme(UserPreferences.getTheme()); + super.onCreate(savedInstanceState); + getSupportActionBar().hide(); + setContentView(R.layout.download_authentication_activity); + + etxtUsername = (EditText) findViewById(R.id.etxtUsername); + etxtPassword = (EditText) findViewById(R.id.etxtPassword); + butConfirm = (Button) findViewById(R.id.butConfirm); + butCancel = (Button) findViewById(R.id.butCancel); + txtvDescription = (TextView) findViewById(R.id.txtvDescription); + + if (!getIntent().hasExtra(ARG_DOWNLOAD_REQUEST)) throw new IllegalArgumentException("Download request missing"); + request = getIntent().getParcelableExtra(ARG_DOWNLOAD_REQUEST); + sendToDownloadRequester = getIntent().getBooleanExtra(ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, false); + + if (savedInstanceState != null) { + etxtUsername.setText(savedInstanceState.getString("username")); + etxtPassword.setText(savedInstanceState.getString("password")); + } + + txtvDescription.setText(txtvDescription.getText() + ":\n\n" + request.getTitle()); + + butCancel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + setResult(Activity.RESULT_CANCELED); + finish(); + } + }); + + butConfirm.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + String username = etxtUsername.getText().toString(); + String password = etxtPassword.getText().toString(); + request.setUsername(username); + request.setPassword(password); + Intent result = new Intent(); + result.putExtra(RESULT_REQUEST, request); + setResult(Activity.RESULT_OK, result); + + if (sendToDownloadRequester) { + if (BuildConfig.DEBUG) Log.d(TAG, "Sending request to DownloadRequester"); + DownloadRequester.getInstance().download(DownloadAuthenticationActivity.this, request); + } + finish(); + } + }); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString("username", etxtUsername.getText().toString()); + outState.putString("password", etxtPassword.getText().toString()); + } +} diff --git a/src/de/danoeh/antennapod/activity/DownloadLogActivity.java b/src/de/danoeh/antennapod/activity/DownloadLogActivity.java index 395e9357b..4629b8670 100644 --- a/src/de/danoeh/antennapod/activity/DownloadLogActivity.java +++ b/src/de/danoeh/antennapod/activity/DownloadLogActivity.java @@ -2,10 +2,8 @@ package de.danoeh.antennapod.activity; import android.os.AsyncTask; import android.os.Bundle; - import android.support.v4.app.NavUtils; import android.support.v7.app.ActionBarActivity; - import android.util.Log; import android.view.Menu; import android.view.MenuItem; diff --git a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java index 37932daf9..db0755ccd 100644 --- a/src/de/danoeh/antennapod/activity/FeedInfoActivity.java +++ b/src/de/danoeh/antennapod/activity/FeedInfoActivity.java @@ -11,7 +11,7 @@ import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.TextView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; @@ -65,9 +65,9 @@ public class FeedInfoActivity extends ActionBarActivity { protected void onPostExecute(Feed result) { if (result != null) { feed = result; - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Language is " + feed.getLanguage()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Author is " + feed.getAuthor()); imgvCover.post(new Runnable() { diff --git a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java index 78d6bcec4..d0305eada 100644 --- a/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java +++ b/src/de/danoeh/antennapod/activity/FeedItemlistActivity.java @@ -2,7 +2,6 @@ package de.danoeh.antennapod.activity; import android.annotation.SuppressLint; import android.app.SearchManager; -import android.app.SearchableInfo; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -17,12 +16,10 @@ import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.SearchView; import android.util.Log; - import android.view.Menu; -import android.view.MenuInflater; import android.view.MenuItem; import android.view.Window; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.FeedRemover; import de.danoeh.antennapod.dialog.ConfirmationDialog; @@ -81,7 +78,7 @@ public class FeedItemlistActivity extends ActionBarActivity { @Override protected Feed doInBackground(Long... longs) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading feed data in background"); return DBReader.getFeed(FeedItemlistActivity.this, longs[0]); } @@ -89,14 +86,14 @@ public class FeedItemlistActivity extends ActionBarActivity { @Override protected void onCancelled(Feed feed) { super.onCancelled(feed); - if (AppConfig.DEBUG) Log.d(TAG, "load task was cancelled"); + if (BuildConfig.DEBUG) Log.d(TAG, "load task was cancelled"); } @Override protected void onPostExecute(Feed result) { super.onPostExecute(result); if (result != null) { - if (AppConfig.DEBUG) Log.d(TAG, "Finished loading feed data"); + if (BuildConfig.DEBUG) Log.d(TAG, "Finished loading feed data"); feed = result; setTitle(feed.getTitle()); diff --git a/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java b/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java index a8335c79a..8dde14d3b 100644 --- a/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java +++ b/src/de/danoeh/antennapod/activity/FlattrAuthActivity.java @@ -1,24 +1,22 @@ package de.danoeh.antennapod.activity; -import android.support.v7.app.ActionBarActivity; -import android.view.Menu; -import android.view.MenuItem; -import org.shredzone.flattr4j.exception.FlattrException; - import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.util.flattr.FlattrUtils; +import org.shredzone.flattr4j.exception.FlattrException; /** Guides the user through the authentication process */ @@ -39,7 +37,7 @@ public class FlattrAuthActivity extends ActionBarActivity { super.onCreate(savedInstanceState); singleton = this; authSuccessful = false; - if (AppConfig.DEBUG) Log.d(TAG, "Activity created"); + if (BuildConfig.DEBUG) Log.d(TAG, "Activity created"); getSupportActionBar().setDisplayHomeAsUpEnabled(true); setContentView(R.layout.flattr_auth); txtvExplanation = (TextView) findViewById(R.id.txtvExplanation); @@ -74,10 +72,10 @@ public class FlattrAuthActivity extends ActionBarActivity { @Override protected void onResume() { super.onResume(); - if (AppConfig.DEBUG) Log.d(TAG, "Activity resumed"); + if (BuildConfig.DEBUG) Log.d(TAG, "Activity resumed"); Uri uri = getIntent().getData(); if (uri != null) { - if (AppConfig.DEBUG) Log.d(TAG, "Received uri"); + if (BuildConfig.DEBUG) Log.d(TAG, "Received uri"); FlattrUtils.handleCallback(this, uri); } } diff --git a/src/de/danoeh/antennapod/activity/ItemviewActivity.java b/src/de/danoeh/antennapod/activity/ItemviewActivity.java index f08686004..699ba84ea 100644 --- a/src/de/danoeh/antennapod/activity/ItemviewActivity.java +++ b/src/de/danoeh/antennapod/activity/ItemviewActivity.java @@ -13,7 +13,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.Window; import android.widget.TextView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.feed.EventDistributor; @@ -75,7 +75,7 @@ public class ItemviewActivity extends ActionBarActivity { if (currentLoadTask != null) { currentLoadTask.cancel(true); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Stopping Activity"); } @@ -93,7 +93,7 @@ public class ItemviewActivity extends ActionBarActivity { @Override protected void onCancelled(FeedItem feedItem) { super.onCancelled(feedItem); - if (AppConfig.DEBUG) Log.d(TAG, "loadTask was cancelled"); + if (BuildConfig.DEBUG) Log.d(TAG, "loadTask was cancelled"); } @Override @@ -192,7 +192,7 @@ public class ItemviewActivity extends ActionBarActivity { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((EVENTS & arg) != 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received contentUpdate Intent."); if (item != null) { loadData(item.getId()); diff --git a/src/de/danoeh/antennapod/activity/MainActivity.java b/src/de/danoeh/antennapod/activity/MainActivity.java index 9edb312de..29e36abc8 100644 --- a/src/de/danoeh/antennapod/activity/MainActivity.java +++ b/src/de/danoeh/antennapod/activity/MainActivity.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.activity; -import java.util.ArrayList; - import android.app.SearchManager; import android.app.SearchableInfo; import android.content.Context; @@ -17,25 +15,26 @@ import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.SearchView; import android.util.Log; - import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.Window; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.fragment.EpisodesFragment; import de.danoeh.antennapod.fragment.ExternalPlayerFragment; import de.danoeh.antennapod.fragment.FeedlistFragment; import de.danoeh.antennapod.preferences.UserPreferences; -import de.danoeh.antennapod.service.playback.PlaybackService; import de.danoeh.antennapod.service.download.DownloadService; +import de.danoeh.antennapod.service.playback.PlaybackService; import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.storage.DBTasks; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.StorageUtils; +import java.util.ArrayList; + /** The activity that is shown when the user launches the app. */ public class MainActivity extends ActionBarActivity { private static final String TAG = "MainActivity"; @@ -121,7 +120,7 @@ public class MainActivity extends ActionBarActivity { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((EVENTS & arg) != 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received contentUpdate Intent."); updateProgressBarVisibility(); } diff --git a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java index 27ac7afd8..fc70f4c05 100644 --- a/src/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/src/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -16,7 +16,7 @@ import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.dialog.TimeDialog; import de.danoeh.antennapod.feed.FeedItem; @@ -135,6 +135,12 @@ public abstract class MediaplayerActivity extends ActionBarActivity public void onPlaybackSpeedChange() { MediaplayerActivity.this.onPlaybackSpeedChange(); } + + @Override + protected void setScreenOn(boolean enable) { + super.setScreenOn(enable); + MediaplayerActivity.this.setScreenOn(enable); + } }; } @@ -151,11 +157,14 @@ public abstract class MediaplayerActivity extends ActionBarActivity setTheme(UserPreferences.getTheme()); } + protected void setScreenOn(boolean enable) { + } + @Override protected void onCreate(Bundle savedInstanceState) { chooseTheme(); super.onCreate(savedInstanceState); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating Activity"); StorageUtils.checkStorageAvailability(this); setVolumeControlStream(AudioManager.STREAM_MUSIC); @@ -213,7 +222,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity @Override protected void onStop() { super.onStop(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Activity stopped"); if (controller != null) { controller.release(); @@ -223,7 +232,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity @Override protected void onDestroy() { super.onDestroy(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Activity destroyed"); } @@ -243,7 +252,8 @@ public abstract class MediaplayerActivity extends ActionBarActivity menu.findItem(R.id.support_item).setVisible( media != null && media.getPaymentLink() != null && (media instanceof FeedMedia) && - ((FeedMedia) media).getItem().getFlattrStatus().flattrable()); + ((FeedMedia) media).getItem().getFlattrStatus().flattrable() + ); menu.findItem(R.id.share_link_item).setVisible( media != null && media.getWebsiteLink() != null); menu.findItem(R.id.visit_website_item).setVisible( @@ -285,7 +295,8 @@ public abstract class MediaplayerActivity extends ActionBarActivity dialog.dismiss(); controller.disableSleepTimer(); } - }); + } + ); stDialog.setNegativeButton(R.string.cancel_label, new DialogInterface.OnClickListener() { @@ -294,7 +305,8 @@ public abstract class MediaplayerActivity extends ActionBarActivity int which) { dialog.dismiss(); } - }); + } + ); stDialog.create().show(); } break; @@ -343,7 +355,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity @Override protected void onResume() { super.onResume(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Resuming Activity"); StorageUtils.checkStorageAvailability(this); controller.init(); @@ -378,7 +390,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity } private void updateProgressbarPosition(int position, int duration) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Updating progressbar info"); float progress = ((float) position) / duration; sbPosition.setProgress((int) (progress * sbPosition.getMax())); @@ -391,7 +403,7 @@ public abstract class MediaplayerActivity extends ActionBarActivity * FeedMedia object. */ protected boolean loadMediaInfo() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading media info"); Playable media = controller.getMedia(); if (media != null) { @@ -451,7 +463,8 @@ public abstract class MediaplayerActivity extends ActionBarActivity dialog.dismiss(); finish(); } - }); + } + ); errorDialog.create().show(); } diff --git a/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java index b5947b41c..6d732b9ff 100644 --- a/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java +++ b/src/de/danoeh/antennapod/activity/MiroGuideCategoryActivity.java @@ -8,7 +8,6 @@ import android.support.v4.app.NavUtils; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBarActivity; import android.util.Log; - import android.view.Menu; import android.view.MenuItem; import de.danoeh.antennapod.R; diff --git a/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java index f1f26a69e..96c8385ce 100644 --- a/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java +++ b/src/de/danoeh/antennapod/activity/MiroGuideChannelViewActivity.java @@ -1,8 +1,5 @@ package de.danoeh.antennapod.activity; -import java.util.Date; -import java.util.List; - import android.annotation.SuppressLint; import android.content.Intent; import android.net.Uri; @@ -15,13 +12,8 @@ import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.RelativeLayout; -import android.widget.TextView; -import android.widget.Toast; - -import de.danoeh.antennapod.AppConfig; +import android.widget.*; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.MiroGuideItemlistAdapter; import de.danoeh.antennapod.dialog.DownloadRequestErrorDialogCreator; @@ -34,6 +26,9 @@ import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; +import java.util.Date; +import java.util.List; + /** * Displays information about one channel and lets the user add this channel to * his library. @@ -95,7 +90,7 @@ public class MiroGuideChannelViewActivity extends ActionBarActivity { @Override protected Void doInBackground(Void... params) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting background task"); feeds = DBReader.getFeedList(MiroGuideChannelViewActivity.this); MiroGuideService service = new MiroGuideService(); @@ -111,7 +106,7 @@ public class MiroGuideChannelViewActivity extends ActionBarActivity { @SuppressLint("NewApi") @Override protected void onPostExecute(Void result) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading finished"); if (exception == null) { txtvTitle.setText(channel.getName()); diff --git a/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java index 66ac09fa5..9f74e77b6 100644 --- a/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java +++ b/src/de/danoeh/antennapod/activity/MiroGuideMainActivity.java @@ -2,7 +2,6 @@ package de.danoeh.antennapod.activity; import android.annotation.SuppressLint; import android.app.SearchManager; -import android.app.SearchableInfo; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; @@ -19,8 +18,7 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.miroguide.conn.MiroGuideException; import de.danoeh.antennapod.miroguide.conn.MiroGuideService; @@ -89,7 +87,7 @@ public class MiroGuideMainActivity extends ActionBarActivity implements AdapterV @Override protected void onPostExecute(Void result) { if (exception == null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Successfully loaded categories"); categories = c; createAdapter(); diff --git a/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java b/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java index c2d88061d..e20253dc6 100644 --- a/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java +++ b/src/de/danoeh/antennapod/activity/MiroGuideSearchActivity.java @@ -7,10 +7,9 @@ import android.support.v4.app.FragmentTransaction; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.util.Log; - import android.view.Menu; import android.view.MenuItem; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.fragment.MiroGuideChannellistFragment; import de.danoeh.antennapod.preferences.UserPreferences; @@ -47,7 +46,7 @@ public class MiroGuideSearchActivity extends ActionBarActivity { } private void handleSearchRequest(String query) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Performing search"); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); listFragment = MiroGuideChannellistFragment.newInstance("name", query, diff --git a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java index 3af4bee7c..6bd5e4eb9 100644 --- a/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java +++ b/src/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java @@ -1,18 +1,21 @@ package de.danoeh.antennapod.activity; import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnCancelListener; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; -import android.view.Gravity; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.RelativeLayout; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.dialog.AuthenticationDialog; import de.danoeh.antennapod.feed.Feed; +import de.danoeh.antennapod.feed.FeedPreferences; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.service.download.DownloadRequest; import de.danoeh.antennapod.service.download.DownloadStatus; @@ -52,9 +55,9 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { private Downloader downloader; @Override - protected void onCreate(Bundle arg0) { + protected void onCreate(Bundle savedInstanceState) { setTheme(UserPreferences.getTheme()); - super.onCreate(arg0); + super.onCreate(savedInstanceState); if (getIntent() != null && getIntent().hasExtra(ARG_TITLE)) { getSupportActionBar().setTitle(getIntent().getStringExtra(ARG_TITLE)); @@ -66,10 +69,23 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { throw new IllegalArgumentException( "Activity must be started with feedurl argument!"); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Activity was started with url " + feedUrl); setLoadingLayout(); - startFeedDownload(feedUrl); + if (savedInstanceState == null) { + startFeedDownload(feedUrl, null, null); + } else { + startFeedDownload(feedUrl, savedInstanceState.getString("username"), savedInstanceState.getString("password")); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (feed != null && feed.getPreferences() != null) { + outState.putString("username", feed.getPreferences().getUsername()); + outState.putString("password", feed.getPreferences().getPassword()); + } } @Override @@ -86,12 +102,16 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { @Override public void run() { - if (AppConfig.DEBUG) Log.d(TAG, "Download was completed"); + if (BuildConfig.DEBUG) Log.d(TAG, "Download was completed"); DownloadStatus status = downloader.getResult(); if (status != null) { if (!status.isCancelled()) { if (status.isSuccessful()) { parseFeed(); + } else if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) { + Dialog dialog = new FeedViewAuthenticationDialog(OnlineFeedViewActivity.this, + R.string.authentication_notification_title, downloader.getDownloadRequest().getSource()); + dialog.show(); } else { String errorMsg = status.getReason().getErrorString( OnlineFeedViewActivity.this); @@ -113,17 +133,20 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { } - private void startFeedDownload(String url) { - if (AppConfig.DEBUG) + private void startFeedDownload(String url, String username, String password) { + if (BuildConfig.DEBUG) Log.d(TAG, "Starting feed download"); url = URLChecker.prepareURL(url); feed = new Feed(url, new Date()); + if (username != null && password != null) { + feed.setPreferences(new FeedPreferences(0, true, username, password)); + } String fileUrl = new File(getExternalCacheDir(), FileNameGenerator.generateFileName(feed.getDownload_url())) .toString(); feed.setFile_url(fileUrl); final DownloadRequest request = new DownloadRequest(feed.getFile_url(), - feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED); + feed.getDownload_url(), "OnlineFeed", 0, Feed.FEEDFILETYPE_FEED, username, password); downloader = new HttpDownloader( request); new Thread() { @@ -163,7 +186,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { "feed must be non-null and downloaded when parseFeed is called"); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Parsing feed"); Thread thread = new Thread() { @@ -190,7 +213,7 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { reasonDetailed = e.getMessage(); } finally { boolean rc = new File(feed.getFile_url()).delete(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Deleted feed source file. Result: " + rc); } @@ -259,4 +282,25 @@ public abstract class OnlineFeedViewActivity extends ActionBarActivity { builder.show(); } + private class FeedViewAuthenticationDialog extends AuthenticationDialog { + + private String feedUrl; + + public FeedViewAuthenticationDialog(Context context, int titleRes, String feedUrl) { + super(context, titleRes, true, false, null, null); + this.feedUrl = feedUrl; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + finish(); + } + + @Override + protected void onConfirmed(String username, String password, boolean saveUsernamePassword) { + startFeedDownload(feedUrl, username, password); + } + } + } diff --git a/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java b/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java index 8f2558c2e..5f2ea0401 100644 --- a/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java +++ b/src/de/danoeh/antennapod/activity/OpmlFeedChooserActivity.java @@ -1,8 +1,5 @@ package de.danoeh.antennapod.activity; -import java.util.ArrayList; -import java.util.List; - import android.content.Intent; import android.os.Bundle; import android.support.v4.view.MenuItemCompat; @@ -15,11 +12,13 @@ import android.view.View.OnClickListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; - import de.danoeh.antennapod.R; import de.danoeh.antennapod.opml.OpmlElement; import de.danoeh.antennapod.preferences.UserPreferences; +import java.util.ArrayList; +import java.util.List; + /** * Displays the feeds that the OPML-Importer has read and lets the user choose * which feeds he wants to import. diff --git a/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java b/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java index 905183aa2..d3fd3949c 100644 --- a/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java +++ b/src/de/danoeh/antennapod/activity/OpmlImportBaseActivity.java @@ -1,17 +1,16 @@ package de.danoeh.antennapod.activity; -import java.io.Reader; -import java.util.ArrayList; - import android.content.Intent; import android.support.v7.app.ActionBarActivity; import android.util.Log; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.asynctask.OpmlFeedQueuer; import de.danoeh.antennapod.asynctask.OpmlImportWorker; import de.danoeh.antennapod.opml.OpmlElement; +import java.io.Reader; +import java.util.ArrayList; + /** * Base activity for Opml Import - e.g. with code what to do afterwards * */ @@ -26,10 +25,10 @@ public class OpmlImportBaseActivity extends ActionBarActivity { */ @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received result"); if (resultCode == RESULT_CANCELED) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Activity was cancelled"); if (finishWhenCanceled()) finish(); @@ -51,7 +50,7 @@ public class OpmlImportBaseActivity extends ActionBarActivity { }; queuer.executeAsync(); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "No items were selected"); } } @@ -67,14 +66,14 @@ public class OpmlImportBaseActivity extends ActionBarActivity { protected void onPostExecute(ArrayList<OpmlElement> result) { super.onPostExecute(result); if (result != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Parsing was successful"); OpmlImportHolder.setReadElements(result); startActivityForResult(new Intent( OpmlImportBaseActivity.this, OpmlFeedChooserActivity.class), 0); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Parser error occurred"); } } diff --git a/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java b/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java index 58e3a96dd..16e663fac 100644 --- a/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java +++ b/src/de/danoeh/antennapod/activity/OpmlImportFromIntentActivity.java @@ -1,14 +1,14 @@ package de.danoeh.antennapod.activity; -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.net.URL; - import android.app.AlertDialog; import android.os.Bundle; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.util.LangUtils; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; + /** Lets the user start the OPML-import process. */ public class OpmlImportFromIntentActivity extends OpmlImportBaseActivity { diff --git a/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java b/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java index a3d679773..94f100321 100644 --- a/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java +++ b/src/de/danoeh/antennapod/activity/OpmlImportFromPathActivity.java @@ -1,12 +1,5 @@ package de.danoeh.antennapod.activity; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.Reader; - import android.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; @@ -18,13 +11,14 @@ import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.util.LangUtils; import de.danoeh.antennapod.util.StorageUtils; +import java.io.*; + /** * Lets the user start the OPML-import process from a path */ @@ -70,7 +64,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { File importDir = UserPreferences.getDataFolder(this, IMPORT_DIR); boolean success = true; if (!importDir.exists()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Import directory doesn't exist. Creating..."); success = importDir.mkdir(); if (!success) { @@ -112,7 +106,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { if (dir.isDirectory()) { File[] fileList = dir.listFiles(); if (fileList.length == 1) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Found one file, choosing that one."); startImport(fileList[0]); } else if (fileList.length > 1) { @@ -133,7 +127,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { try { mReader = new InputStreamReader(new FileInputStream(file), LangUtils.UTF_8); - if (AppConfig.DEBUG) Log.d(TAG, "Parsing " + file.toString()); + if (BuildConfig.DEBUG) Log.d(TAG, "Parsing " + file.toString()); startImport(mReader); } catch (FileNotFoundException e) { Log.d(TAG, "File not found which really should be there"); @@ -156,7 +150,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { @Override public void onClick(DialogInterface dialog, int which) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Dialog was cancelled"); dialog.dismiss(); } @@ -165,7 +159,7 @@ public class OpmlImportFromPathActivity extends OpmlImportBaseActivity { @Override public void onClick(DialogInterface dialog, int which) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "File at index " + which + " was chosen"); dialog.dismiss(); startImport(fileList[which]); diff --git a/src/de/danoeh/antennapod/activity/OpmlImportHolder.java b/src/de/danoeh/antennapod/activity/OpmlImportHolder.java index 8d51eb3de..ec53ed7b6 100644 --- a/src/de/danoeh/antennapod/activity/OpmlImportHolder.java +++ b/src/de/danoeh/antennapod/activity/OpmlImportHolder.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.activity; -import java.util.ArrayList; - import de.danoeh.antennapod.opml.OpmlElement; +import java.util.ArrayList; + /** * Hold infos gathered by Ompl-Import * <p/> diff --git a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java index 5ed1dd09a..6e2cf597f 100644 --- a/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java +++ b/src/de/danoeh/antennapod/activity/OrganizeQueueActivity.java @@ -5,18 +5,13 @@ import android.os.AsyncTask; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; -import android.support.v4.app.NavUtils; import android.support.v7.app.ActionBarActivity; -import android.view.*; import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; +import android.view.*; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; - import com.mobeta.android.dslv.DragSortListView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.ImageLoader; diff --git a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java b/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java index 0460458eb..ba3d12105 100644 --- a/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java +++ b/src/de/danoeh/antennapod/activity/PlaybackHistoryActivity.java @@ -1,16 +1,13 @@ package de.danoeh.antennapod.activity; -import android.content.Intent; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; -import android.support.v4.app.NavUtils; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBarActivity; import android.util.Log; - import android.view.Menu; import android.view.MenuItem; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.fragment.PlaybackHistoryFragment; import de.danoeh.antennapod.preferences.UserPreferences; @@ -46,7 +43,7 @@ public class PlaybackHistoryActivity extends ActionBarActivity { setTheme(UserPreferences.getTheme()); super.onCreate(arg0); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Activity created"); getSupportActionBar().setDisplayHomeAsUpEnabled(true); setContentView(R.layout.playbackhistory_activity); diff --git a/src/de/danoeh/antennapod/activity/PreferenceActivity.java b/src/de/danoeh/antennapod/activity/PreferenceActivity.java index 4a8dc1882..1070c71f8 100644 --- a/src/de/danoeh/antennapod/activity/PreferenceActivity.java +++ b/src/de/danoeh/antennapod/activity/PreferenceActivity.java @@ -19,7 +19,7 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.FlattrClickWorker; import de.danoeh.antennapod.asynctask.OpmlExportWorker; @@ -362,7 +362,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity { if (resultCode == DirectoryChooserActivity.RESULT_CODE_DIR_SELECTED) { String dir = data .getStringExtra(DirectoryChooserActivity.RESULT_SELECTED_DIR); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Setting data folder"); UserPreferences.setDataFolder(dir); } @@ -392,7 +392,7 @@ public class PreferenceActivity extends android.preference.PreferenceActivity { .getAutodownloadSelectedNetworks())); boolean newValue = ((CheckBoxPreference) preference) .isChecked(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Selected network " + key + ". New state: " + newValue); diff --git a/src/de/danoeh/antennapod/activity/SearchActivity.java b/src/de/danoeh/antennapod/activity/SearchActivity.java index c31cec434..f330aeb7d 100644 --- a/src/de/danoeh/antennapod/activity/SearchActivity.java +++ b/src/de/danoeh/antennapod/activity/SearchActivity.java @@ -1,8 +1,5 @@ package de.danoeh.antennapod.activity; -import java.util.ArrayList; -import java.util.List; - import android.annotation.SuppressLint; import android.app.Activity; import android.app.SearchManager; @@ -17,17 +14,19 @@ import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import android.widget.TextView; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.adapter.SearchlistAdapter; import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedItem; -import de.danoeh.antennapod.storage.FeedSearcher; import de.danoeh.antennapod.feed.SearchResult; import de.danoeh.antennapod.fragment.FeedlistFragment; import de.danoeh.antennapod.fragment.ItemlistFragment; import de.danoeh.antennapod.preferences.UserPreferences; +import de.danoeh.antennapod.storage.FeedSearcher; + +import java.util.ArrayList; +import java.util.List; /** * Displays the results when the user searches for FeedItems or Feeds. @@ -75,11 +74,11 @@ public class SearchActivity extends ActionBarActivity implements AdapterView.OnI Intent intent = getIntent(); if (Intent.ACTION_SEARCH.equals(intent.getAction())) { if (intent.hasExtra(SearchActivity.EXTRA_FEED_ID)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Found bundle extra"); feedID = intent.getLongExtra(SearchActivity.EXTRA_FEED_ID, 0); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting search"); String query = intent.getStringExtra(SearchManager.QUERY); getSupportActionBar() @@ -149,9 +148,9 @@ public class SearchActivity extends ActionBarActivity implements AdapterView.OnI @Override public void run() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Background work finished"); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Found " + result.size() + " results"); diff --git a/src/de/danoeh/antennapod/activity/StorageErrorActivity.java b/src/de/danoeh/antennapod/activity/StorageErrorActivity.java index 33277ebc9..2cd56ba8b 100644 --- a/src/de/danoeh/antennapod/activity/StorageErrorActivity.java +++ b/src/de/danoeh/antennapod/activity/StorageErrorActivity.java @@ -7,8 +7,7 @@ import android.content.IntentFilter; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.util.Log; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.util.StorageUtils; @@ -57,11 +56,11 @@ public class StorageErrorActivity extends ActionBarActivity { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED)) { if (intent.getBooleanExtra("read-only", true)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Media was mounted; Finishing activity"); leaveErrorState(); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Media seemed to have been mounted read only"); } diff --git a/src/de/danoeh/antennapod/activity/VideoplayerActivity.java b/src/de/danoeh/antennapod/activity/VideoplayerActivity.java index 489d57340..c45a3d162 100644 --- a/src/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/src/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -14,7 +14,7 @@ import android.view.animation.AnimationUtils; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.SeekBar; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.feed.MediaType; import de.danoeh.antennapod.service.playback.PlaybackService; @@ -72,7 +72,7 @@ public class VideoplayerActivity extends MediaplayerActivity { if (getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_VIEW)) { Intent intent = getIntent(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received VIEW intent: " + intent.getData().getPath()); ExternalMedia media = new ExternalMedia(intent.getData().getPath(), @@ -120,13 +120,13 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override protected void onAwaitingVideoSurface() { if (videoSurfaceCreated) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Videosurface already created, setting videosurface now"); Pair<Integer, Integer> videoSize = controller.getVideoSize(); if (videoSize != null && videoSize.first > 0 && videoSize.second > 0) { - if (AppConfig.DEBUG) Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second); + if (BuildConfig.DEBUG) Log.d(TAG, "Width,height of video: " + videoSize.first + ", " + videoSize.second); videoview.setVideoSize(videoSize.first, videoSize.second); } else { Log.e(TAG, "Could not determine video size"); @@ -215,7 +215,7 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override protected void onProgressUpdate(Void... values) { if (videoControlsShowing) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Hiding video controls"); getSupportActionBar().hide(); hideVideoControls(); @@ -245,7 +245,7 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override public void surfaceCreated(SurfaceHolder holder) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Videoview holder created"); videoSurfaceCreated = true; if (controller.getStatus() == PlayerStatus.PLAYING) { @@ -261,7 +261,7 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override public void surfaceDestroyed(SurfaceHolder holder) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Videosurface was destroyed"); videoSurfaceCreated = false; controller.notifyVideoSurfaceAbandoned(); @@ -272,7 +272,7 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override protected void onReloadNotification(int notificationCode) { if (notificationCode == PlaybackService.EXTRA_CODE_AUDIO) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "ReloadNotification received, switching to Audioplayer now"); finish(); @@ -337,4 +337,14 @@ public class VideoplayerActivity extends MediaplayerActivity { return R.layout.videoplayer_activity; } + + @Override + protected void setScreenOn(boolean enable) { + super.setScreenOn(enable); + if (enable) { + getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } else { + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } + } } diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java index e5a00923a..05048f079 100644 --- a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetAuthenticationActivity.java @@ -12,7 +12,7 @@ import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.widget.*; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.gpoddernet.GpodnetService; @@ -113,7 +113,7 @@ public class GpodnetAuthenticationActivity extends ActionBarActivity { final String usernameStr = username.getText().toString(); final String passwordStr = password.getText().toString(); - if (AppConfig.DEBUG) Log.d(TAG, "Checking login credentials"); + if (BuildConfig.DEBUG) Log.d(TAG, "Checking login credentials"); new AsyncTask<GpodnetService, Void, Void>() { volatile Exception exception; @@ -333,7 +333,7 @@ public class GpodnetAuthenticationActivity extends ActionBarActivity { } private void writeLoginCredentials() { - if (AppConfig.DEBUG) Log.d(TAG, "Writing login credentials"); + if (BuildConfig.DEBUG) Log.d(TAG, "Writing login credentials"); GpodnetPreferences.setUsername(username); GpodnetPreferences.setPassword(password); GpodnetPreferences.setDeviceID(selectedDevice.getId()); diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java index 9535e9d32..e77a6a7a3 100644 --- a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetMainActivity.java @@ -11,7 +11,6 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.fragment.gpodnet.PodcastTopListFragment; import de.danoeh.antennapod.fragment.gpodnet.SuggestionListFragment; import de.danoeh.antennapod.fragment.gpodnet.TagListFragment; -import de.danoeh.antennapod.preferences.GpodnetPreferences; /** * Created by daniel on 22.08.13. diff --git a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java index f3922f7aa..14897c60c 100644 --- a/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java +++ b/src/de/danoeh/antennapod/activity/gpoddernet/GpodnetTagActivity.java @@ -7,7 +7,6 @@ import android.support.v4.app.NavUtils; import android.view.MenuItem; import de.danoeh.antennapod.R; import de.danoeh.antennapod.fragment.gpodnet.PodcastListFragment; -import de.danoeh.antennapod.fragment.gpodnet.SearchListFragment; import de.danoeh.antennapod.gpoddernet.GpodnetService; import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; diff --git a/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java index 116c39ddf..72ad6774f 100644 --- a/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/ChapterListAdapter.java @@ -1,13 +1,10 @@ package de.danoeh.antennapod.adapter; -import java.util.List; - import android.content.Context; import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.Spanned; -import android.text.method.LinkMovementMethod; import android.text.style.ClickableSpan; import android.text.util.Linkify; import android.util.Log; @@ -24,6 +21,8 @@ import de.danoeh.antennapod.util.ChapterUtils; import de.danoeh.antennapod.util.Converter; import de.danoeh.antennapod.util.playback.Playable; +import java.util.List; + public class ChapterListAdapter extends ArrayAdapter<Chapter> { private static final String TAG = "ChapterListAdapter"; diff --git a/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java index c067ac5d2..e97d69494 100644 --- a/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java +++ b/src/de/danoeh/antennapod/adapter/DownloadLogAdapter.java @@ -12,7 +12,6 @@ import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedImage; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.service.download.DownloadStatus; -import de.danoeh.antennapod.util.DownloadError; /** Displays a list of DownloadStatus entries. */ public class DownloadLogAdapter extends BaseAdapter { diff --git a/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java b/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java index 75e837969..2739d2f27 100644 --- a/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/DownloadlistAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.util.List; - import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -10,16 +8,14 @@ import android.widget.ArrayAdapter; import android.widget.ProgressBar; import android.widget.TextView; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.feed.Feed; -import de.danoeh.antennapod.feed.FeedFile; -import de.danoeh.antennapod.feed.FeedImage; -import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.service.download.DownloadRequest; import de.danoeh.antennapod.service.download.DownloadStatus; import de.danoeh.antennapod.service.download.Downloader; import de.danoeh.antennapod.util.Converter; import de.danoeh.antennapod.util.ThemeUtils; +import java.util.List; + public class DownloadlistAdapter extends ArrayAdapter<Downloader> { private int selectedItemIndex; diff --git a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java index aed988b59..aa724f991 100644 --- a/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/ExternalEpisodesListAdapter.java @@ -6,11 +6,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.BaseExpandableListAdapter; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; +import android.widget.*; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.feed.FeedItem; diff --git a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java index 238ae29c6..4681284f5 100644 --- a/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/InternalFeedItemlistAdapter.java @@ -7,11 +7,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.Adapter; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; +import android.widget.*; import de.danoeh.antennapod.R; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedMedia; @@ -20,8 +16,6 @@ import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.Converter; import de.danoeh.antennapod.util.ThemeUtils; -import java.util.Iterator; - /** List adapter for items of feeds that the user has already subscribed to. */ public class InternalFeedItemlistAdapter extends DefaultFeedItemlistAdapter { diff --git a/src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java b/src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java index 0ac58e7a4..4361b3af8 100644 --- a/src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java +++ b/src/de/danoeh/antennapod/adapter/MiroGuideChannelListAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.util.List; - import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -11,6 +9,8 @@ import android.widget.TextView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.miroguide.model.MiroGuideChannel; +import java.util.List; + public class MiroGuideChannelListAdapter extends ArrayAdapter<MiroGuideChannel> { public MiroGuideChannelListAdapter(Context context, int textViewResourceId, diff --git a/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java b/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java index f12345f84..18a4b42cc 100644 --- a/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/MiroGuideItemlistAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.util.List; - import android.content.Context; import android.text.format.DateUtils; import android.view.LayoutInflater; @@ -12,6 +10,8 @@ import android.widget.TextView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.miroguide.model.MiroGuideItem; +import java.util.List; + public class MiroGuideItemlistAdapter extends ArrayAdapter<MiroGuideItem> { public MiroGuideItemlistAdapter(Context context, int textViewResourceId, diff --git a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java index 129289d30..926a5a5ad 100644 --- a/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java +++ b/src/de/danoeh/antennapod/adapter/SearchlistAdapter.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.adapter; -import java.util.List; - import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -16,6 +14,8 @@ import de.danoeh.antennapod.feed.FeedComponent; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.SearchResult; +import java.util.List; + /** List adapter for search activity. */ public class SearchlistAdapter extends ArrayAdapter<SearchResult> { diff --git a/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java b/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java index ef70c1e64..43118c3af 100644 --- a/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java +++ b/src/de/danoeh/antennapod/asynctask/BitmapDecodeWorkerTask.java @@ -1,6 +1,5 @@ package de.danoeh.antennapod.asynctask; -import android.content.res.TypedArray; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -8,7 +7,7 @@ import android.graphics.drawable.TransitionDrawable; import android.os.Handler; import android.util.Log; import android.widget.ImageView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.ImageLoader.ImageWorkerTaskResource; @@ -65,7 +64,7 @@ public class BitmapDecodeWorkerTask extends Thread { target.setImageDrawable(transitionDrawable); transitionDrawable.startTransition(FADE_DURATION); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Not displaying image"); } } @@ -82,7 +81,7 @@ public class BitmapDecodeWorkerTask extends Thread { target.getResources(), defaultCoverResource), PREFERRED_LENGTH); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Finished loading bitmaps"); endBackgroundTask(); diff --git a/src/de/danoeh/antennapod/asynctask/DownloadObserver.java b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java index 26e405615..40388cde5 100644 --- a/src/de/danoeh/antennapod/asynctask/DownloadObserver.java +++ b/src/de/danoeh/antennapod/asynctask/DownloadObserver.java @@ -5,7 +5,7 @@ import android.content.*; import android.os.Handler; import android.os.IBinder; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.service.download.DownloadService; import de.danoeh.antennapod.service.download.Downloader; @@ -55,13 +55,13 @@ public class DownloadObserver { } public void onResume() { - if (AppConfig.DEBUG) Log.d(TAG, "DownloadObserver resumed"); + if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver resumed"); activity.registerReceiver(contentChangedReceiver, new IntentFilter(DownloadService.ACTION_DOWNLOADS_CONTENT_CHANGED)); activity.bindService(new Intent(activity, DownloadService.class), mConnection, 0); } public void onPause() { - if (AppConfig.DEBUG) Log.d(TAG, "DownloadObserver paused"); + if (BuildConfig.DEBUG) Log.d(TAG, "DownloadObserver paused"); activity.unregisterReceiver(contentChangedReceiver); activity.unbindService(mConnection); stopRefresher(); @@ -93,7 +93,7 @@ public class DownloadObserver { downloadService = ((DownloadService.LocalBinder) service) .getService(); mIsBound.set(true); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Connection to service established"); List<Downloader> downloaderList = downloadService.getDownloads(); if (downloaderList != null && !downloaderList.isEmpty()) { diff --git a/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java b/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java index 5f483625a..e9aa79ac1 100644 --- a/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java +++ b/src/de/danoeh/antennapod/asynctask/FlattrClickWorker.java @@ -13,7 +13,7 @@ import android.os.AsyncTask; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.widget.Toast; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MainActivity; import de.danoeh.antennapod.storage.DBReader; @@ -23,7 +23,6 @@ import de.danoeh.antennapod.util.flattr.FlattrUtils; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.Executor; /** * Performs a click action in a background thread. @@ -200,7 +199,7 @@ public class FlattrClickWorker extends AsyncTask<Void, String, Void> { @Override protected void onPostExecute(Void result) { - if (AppConfig.DEBUG) Log.d(TAG, "Exit code was " + exitCode); + if (BuildConfig.DEBUG) Log.d(TAG, "Exit code was " + exitCode); switch (exitCode) { case NO_TOKEN: @@ -234,7 +233,7 @@ public class FlattrClickWorker extends AsyncTask<Void, String, Void> { @Override protected Void doInBackground(Void... params) { - if (AppConfig.DEBUG) Log.d(TAG, "Starting background work"); + if (BuildConfig.DEBUG) Log.d(TAG, "Starting background work"); exitCode = EXIT_DEFAULT; diff --git a/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java b/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java index 4974c6b56..04d349671 100644 --- a/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java +++ b/src/de/danoeh/antennapod/asynctask/FlattrStatusFetcher.java @@ -2,7 +2,7 @@ package de.danoeh.antennapod.asynctask; import android.content.Context; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.storage.DBWriter; import de.danoeh.antennapod.util.flattr.FlattrUtils; import org.shredzone.flattr4j.exception.FlattrException; @@ -26,7 +26,7 @@ public class FlattrStatusFetcher extends Thread { @Override public void run() { - if (AppConfig.DEBUG) Log.d(TAG, "Starting background work: Retrieving Flattr status"); + if (BuildConfig.DEBUG) Log.d(TAG, "Starting background work: Retrieving Flattr status"); Thread.currentThread().setPriority(Thread.MIN_PRIORITY); @@ -42,6 +42,6 @@ public class FlattrStatusFetcher extends Thread { e.printStackTrace(); } - if (AppConfig.DEBUG) Log.d(TAG, "Finished background work: Retrieved Flattr status"); + if (BuildConfig.DEBUG) Log.d(TAG, "Finished background work: Retrieved Flattr status"); } } diff --git a/src/de/danoeh/antennapod/asynctask/FlattrTokenFetcher.java b/src/de/danoeh/antennapod/asynctask/FlattrTokenFetcher.java index b56e83d25..0dcf832f7 100644 --- a/src/de/danoeh/antennapod/asynctask/FlattrTokenFetcher.java +++ b/src/de/danoeh/antennapod/asynctask/FlattrTokenFetcher.java @@ -1,20 +1,19 @@ package de.danoeh.antennapod.asynctask; -import org.shredzone.flattr4j.exception.FlattrException; -import org.shredzone.flattr4j.oauth.AccessToken; -import org.shredzone.flattr4j.oauth.AndroidAuthenticator; - import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.Context; import android.net.Uri; import android.os.AsyncTask; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.FlattrAuthActivity; import de.danoeh.antennapod.util.flattr.FlattrUtils; +import org.shredzone.flattr4j.exception.FlattrException; +import org.shredzone.flattr4j.oauth.AccessToken; +import org.shredzone.flattr4j.oauth.AndroidAuthenticator; /** Fetches the access token in the background in order to avoid networkOnMainThread exception. */ @@ -76,7 +75,7 @@ public class FlattrTokenFetcher extends AsyncTask<Void, Void, AccessToken> { return null; } if (token != null) { - if (AppConfig.DEBUG) Log.d(TAG, "Successfully got token"); + if (BuildConfig.DEBUG) Log.d(TAG, "Successfully got token"); return token; } else { Log.w(TAG, "Flattr token was null"); diff --git a/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java b/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java index ae8bf8b87..b90d78c14 100644 --- a/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java +++ b/src/de/danoeh/antennapod/asynctask/ImageDiskCache.java @@ -4,7 +4,7 @@ import android.os.Handler; import android.util.Log; import android.util.Pair; import android.widget.ImageView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; import de.danoeh.antennapod.service.download.DownloadRequest; @@ -89,7 +89,7 @@ public class ImageDiskCache { private synchronized void initCacheFolder() { if (diskCache == null) { - if (AppConfig.DEBUG) Log.d(TAG, "Initializing cache folder"); + if (BuildConfig.DEBUG) Log.d(TAG, "Initializing cache folder"); File cacheFile = new File(cacheFolder, CACHE_FILE_NAME); if (cacheFile.exists()) { try { @@ -242,7 +242,7 @@ public class ImageDiskCache { if (diskCache == null) { initCacheFolder(); } - if (AppConfig.DEBUG) Log.d(TAG, "Adding new image to disk cache: " + url); + if (BuildConfig.DEBUG) Log.d(TAG, "Adding new image to disk cache: " + url); diskCache.put(url, obj); cacheSize += obj.size; if (cacheSize > maxCacheSize) { @@ -313,7 +313,7 @@ public class ImageDiskCache { dco = new DiskCacheObject(newFile.getAbsolutePath(), size); addToDiskCache(downloadUrl, dco); - if (AppConfig.DEBUG) Log.d(TAG, "Image was downloaded"); + if (BuildConfig.DEBUG) Log.d(TAG, "Image was downloaded"); } else { Log.w(TAG, "Download of url " + downloadUrl + " failed. Reason: " + result.getResult().getReasonDetailed() + "(" + result.getResult().getReason() + ")"); } diff --git a/src/de/danoeh/antennapod/asynctask/ImageLoader.java b/src/de/danoeh/antennapod/asynctask/ImageLoader.java index a4a9bc823..6c60b7b1f 100644 --- a/src/de/danoeh/antennapod/asynctask/ImageLoader.java +++ b/src/de/danoeh/antennapod/asynctask/ImageLoader.java @@ -1,230 +1,246 @@ package de.danoeh.antennapod.asynctask; -import java.io.InputStream; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ThreadFactory; - import android.annotation.SuppressLint; import android.app.ActivityManager; import android.content.Context; -import android.content.res.TypedArray; import android.os.Handler; import android.support.v4.util.LruCache; import android.util.Log; import android.widget.ImageView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; -/** Caches and loads FeedImage bitmaps in the background */ +import java.io.InputStream; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; + +/** + * Caches and loads FeedImage bitmaps in the background + */ public class ImageLoader { - private static final String TAG = "ImageLoader"; - private static ImageLoader singleton; - - public static final int IMAGE_TYPE_THUMBNAIL = 0; - public static final int IMAGE_TYPE_COVER = 1; - - private Handler handler; - private ExecutorService executor; - - /** - * Stores references to loaded bitmaps. Bitmaps can be accessed by the id of - * the FeedImage the bitmap belongs to. - */ - - final int memClass = ((ActivityManager) PodcastApp.getInstance() - .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass(); - - // Use 1/8th of the available memory for this memory cache. - final int thumbnailCacheSize = 1024 * 1024 * memClass / 8; - - private LruCache<String, CachedBitmap> coverCache; - private LruCache<String, CachedBitmap> thumbnailCache; - - private ImageLoader() { - handler = new Handler(); - executor = createExecutor(); - - coverCache = new LruCache<String, CachedBitmap>(1); - - thumbnailCache = new LruCache<String, CachedBitmap>(thumbnailCacheSize) { - - @SuppressLint("NewApi") - @Override - protected int sizeOf(String key, CachedBitmap value) { - if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12) - return value.getBitmap().getByteCount(); - else - return (value.getBitmap().getRowBytes() * value.getBitmap() - .getHeight()); - - } - - }; - } - - private ExecutorService createExecutor() { - return Executors.newFixedThreadPool(Runtime.getRuntime() - .availableProcessors(), new ThreadFactory() { - - @Override - public Thread newThread(Runnable r) { - Thread t = new Thread(r); - t.setPriority(Thread.MIN_PRIORITY); - return t; - } - }); - } - - public static synchronized ImageLoader getInstance() { - if (singleton == null) { - singleton = new ImageLoader(); - } - return singleton; - } - - /** - * Load a bitmap from the cover cache. If the bitmap is not in the cache, it - * will be loaded from the disk. This method should either be called if the - * ImageView's size has already been set or inside a Runnable which is - * posted to the ImageView's message queue. - */ - public void loadCoverBitmap(ImageWorkerTaskResource source, ImageView target) { - loadCoverBitmap(source, target, target.getHeight()); - } - - /** - * Load a bitmap from the cover cache. If the bitmap is not in the cache, it - * will be loaded from the disk. This method should either be called if the - * ImageView's size has already been set or inside a Runnable which is - * posted to the ImageView's message queue. - */ - public void loadCoverBitmap(ImageWorkerTaskResource source, - ImageView target, int length) { - final int defaultCoverResource = getDefaultCoverResource(target - .getContext()); - - if (source != null && source.getImageLoaderCacheKey() != null) { - target.setTag(R.id.imageloader_key, source.getImageLoaderCacheKey()); - CachedBitmap cBitmap = getBitmapFromCoverCache(source.getImageLoaderCacheKey()); - if (cBitmap != null && cBitmap.getLength() >= length) { - target.setImageBitmap(cBitmap.getBitmap()); - } else { - target.setImageResource(defaultCoverResource); - BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask( - handler, target, source, length, IMAGE_TYPE_COVER); - executor.submit(worker); - } - } else { - target.setImageResource(defaultCoverResource); - } - } - - /** - * Load a bitmap from the thumbnail cache. If the bitmap is not in the - * cache, it will be loaded from the disk. This method should either be - * called if the ImageView's size has already been set or inside a Runnable - * which is posted to the ImageView's message queue. - */ - public void loadThumbnailBitmap(ImageWorkerTaskResource source, - ImageView target) { - loadThumbnailBitmap(source, target, target.getHeight()); - } - - /** - * Load a bitmap from the thumbnail cache. If the bitmap is not in the - * cache, it will be loaded from the disk. This method should either be - * called if the ImageView's size has already been set or inside a Runnable - * which is posted to the ImageView's message queue. - */ - public void loadThumbnailBitmap(ImageWorkerTaskResource source, - ImageView target, int length) { - final int defaultCoverResource = getDefaultCoverResource(target - .getContext()); - - if (source != null && source.getImageLoaderCacheKey() != null) { - target.setTag(R.id.imageloader_key, source.getImageLoaderCacheKey()); - CachedBitmap cBitmap = getBitmapFromThumbnailCache(source.getImageLoaderCacheKey()); - if (cBitmap != null && cBitmap.getLength() >= length) { - target.setImageBitmap(cBitmap.getBitmap()); - } else { - target.setImageResource(defaultCoverResource); - BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask( - handler, target, source, length, IMAGE_TYPE_THUMBNAIL); - executor.submit(worker); - } - } else { - target.setImageResource(defaultCoverResource); - } - } - - public void clearExecutorQueue() { - executor.shutdownNow(); - if (AppConfig.DEBUG) - Log.d(TAG, "Executor was shut down."); - executor = createExecutor(); - - } - - public void wipeImageCache() { - coverCache.evictAll(); - thumbnailCache.evictAll(); - } - - public boolean isInThumbnailCache(String fileUrl) { - return thumbnailCache.get(fileUrl) != null; - } - - private CachedBitmap getBitmapFromThumbnailCache(String key) { - return thumbnailCache.get(key); - } - - public void addBitmapToThumbnailCache(String key, CachedBitmap bitmap) { - thumbnailCache.put(key, bitmap); - } - - public boolean isInCoverCache(String fileUrl) { - return coverCache.get(fileUrl) != null; - } - - private CachedBitmap getBitmapFromCoverCache(String key) { - return coverCache.get(key); - } - - public void addBitmapToCoverCache(String key, CachedBitmap bitmap) { - coverCache.put(key, bitmap); - } - - private int getDefaultCoverResource(Context context) { - return android.R.color.transparent; - } - - /** - * Used by the BitmapDecodeWorker task to retrieve the source of the bitmap. - */ - public interface ImageWorkerTaskResource { - /** - * Opens a new InputStream that can be decoded as a bitmap by the - * BitmapFactory. - */ - public InputStream openImageInputStream(); - - /** - * Returns an InputStream that points to the beginning of the image - * resource. Implementations can either create a new InputStream or - * reset the existing one, depending on their implementation of - * openInputStream. If a new InputStream is returned, the one given as a - * parameter MUST be closed. - * @param input The input stream that was returned by openImageInputStream() - * */ - public InputStream reopenImageInputStream(InputStream input); - - /** - * Returns a string that identifies the image resource. Example: file - * path of an image - */ - public String getImageLoaderCacheKey(); - } + private static final String TAG = "ImageLoader"; + private static ImageLoader singleton; + + public static final int IMAGE_TYPE_THUMBNAIL = 0; + public static final int IMAGE_TYPE_COVER = 1; + + /** + * Used by loadThumbnailBitmap and loadCoverBitmap to denote an ImageView that displays the default image resource. + * This is the case if the given source to load the image from was null or did not return any image data. + */ + private static final Object DEFAULT_IMAGE_RESOURCE_TAG = new Object(); + + private Handler handler; + private ExecutorService executor; + + /** + * Stores references to loaded bitmaps. Bitmaps can be accessed by the id of + * the FeedImage the bitmap belongs to. + */ + + final int memClass = ((ActivityManager) PodcastApp.getInstance() + .getSystemService(Context.ACTIVITY_SERVICE)).getMemoryClass(); + + // Use 1/8th of the available memory for this memory cache. + final int thumbnailCacheSize = 1024 * 1024 * memClass / 8; + + private LruCache<String, CachedBitmap> coverCache; + private LruCache<String, CachedBitmap> thumbnailCache; + + private ImageLoader() { + handler = new Handler(); + executor = createExecutor(); + + coverCache = new LruCache<String, CachedBitmap>(1); + + thumbnailCache = new LruCache<String, CachedBitmap>(thumbnailCacheSize) { + + @SuppressLint("NewApi") + @Override + protected int sizeOf(String key, CachedBitmap value) { + if (Integer.valueOf(android.os.Build.VERSION.SDK_INT) >= 12) + return value.getBitmap().getByteCount(); + else + return (value.getBitmap().getRowBytes() * value.getBitmap() + .getHeight()); + + } + + }; + } + + private ExecutorService createExecutor() { + return Executors.newFixedThreadPool(Runtime.getRuntime() + .availableProcessors(), new ThreadFactory() { + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r); + t.setPriority(Thread.MIN_PRIORITY); + return t; + } + }); + } + + public static synchronized ImageLoader getInstance() { + if (singleton == null) { + singleton = new ImageLoader(); + } + return singleton; + } + + /** + * Load a bitmap from the cover cache. If the bitmap is not in the cache, it + * will be loaded from the disk. This method should either be called if the + * ImageView's size has already been set or inside a Runnable which is + * posted to the ImageView's message queue. + */ + public void loadCoverBitmap(ImageWorkerTaskResource source, ImageView target) { + loadCoverBitmap(source, target, target.getHeight()); + } + + /** + * Load a bitmap from the cover cache. If the bitmap is not in the cache, it + * will be loaded from the disk. This method should either be called if the + * ImageView's size has already been set or inside a Runnable which is + * posted to the ImageView's message queue. + */ + public void loadCoverBitmap(ImageWorkerTaskResource source, + ImageView target, int length) { + final int defaultCoverResource = getDefaultCoverResource(target + .getContext()); + final String cacheKey; + if (source != null && (cacheKey = source.getImageLoaderCacheKey()) != null) { + final Object currentTag = target.getTag(R.id.imageloader_key); + if (currentTag == null || !cacheKey.equals(currentTag)) { + target.setTag(R.id.imageloader_key, cacheKey); + CachedBitmap cBitmap = getBitmapFromCoverCache(cacheKey); + if (cBitmap != null && cBitmap.getLength() >= length) { + target.setImageBitmap(cBitmap.getBitmap()); + } else { + target.setImageResource(defaultCoverResource); + BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask( + handler, target, source, length, IMAGE_TYPE_COVER); + executor.submit(worker); + } + } + } else { + target.setImageResource(defaultCoverResource); + target.setTag(R.id.imageloader_key, DEFAULT_IMAGE_RESOURCE_TAG); + } + } + + /** + * Load a bitmap from the thumbnail cache. If the bitmap is not in the + * cache, it will be loaded from the disk. This method should either be + * called if the ImageView's size has already been set or inside a Runnable + * which is posted to the ImageView's message queue. + */ + public void loadThumbnailBitmap(ImageWorkerTaskResource source, + ImageView target) { + loadThumbnailBitmap(source, target, target.getHeight()); + } + + /** + * Load a bitmap from the thumbnail cache. If the bitmap is not in the + * cache, it will be loaded from the disk. This method should either be + * called if the ImageView's size has already been set or inside a Runnable + * which is posted to the ImageView's message queue. + */ + public void loadThumbnailBitmap(ImageWorkerTaskResource source, + ImageView target, int length) { + final int defaultCoverResource = getDefaultCoverResource(target + .getContext()); + final String cacheKey; + if (source != null && (cacheKey = source.getImageLoaderCacheKey()) != null) { + final Object currentTag = target.getTag(R.id.imageloader_key); + if (currentTag == null || !cacheKey.equals(currentTag)) { + target.setTag(R.id.imageloader_key, cacheKey); + CachedBitmap cBitmap = getBitmapFromThumbnailCache(cacheKey); + if (cBitmap != null && cBitmap.getLength() >= length) { + target.setImageBitmap(cBitmap.getBitmap()); + } else { + target.setImageResource(defaultCoverResource); + BitmapDecodeWorkerTask worker = new BitmapDecodeWorkerTask( + handler, target, source, length, IMAGE_TYPE_THUMBNAIL); + executor.submit(worker); + } + } + } else { + target.setImageResource(defaultCoverResource); + target.setTag(R.id.imageloader_key, DEFAULT_IMAGE_RESOURCE_TAG); + } + } + + public void clearExecutorQueue() { + executor.shutdownNow(); + if (BuildConfig.DEBUG) + Log.d(TAG, "Executor was shut down."); + executor = createExecutor(); + + } + + public void wipeImageCache() { + coverCache.evictAll(); + thumbnailCache.evictAll(); + } + + public boolean isInThumbnailCache(String fileUrl) { + return thumbnailCache.get(fileUrl) != null; + } + + private CachedBitmap getBitmapFromThumbnailCache(String key) { + return thumbnailCache.get(key); + } + + public void addBitmapToThumbnailCache(String key, CachedBitmap bitmap) { + thumbnailCache.put(key, bitmap); + } + + public boolean isInCoverCache(String fileUrl) { + return coverCache.get(fileUrl) != null; + } + + private CachedBitmap getBitmapFromCoverCache(String key) { + return coverCache.get(key); + } + + public void addBitmapToCoverCache(String key, CachedBitmap bitmap) { + coverCache.put(key, bitmap); + } + + private int getDefaultCoverResource(Context context) { + return android.R.color.transparent; + } + + /** + * Used by the BitmapDecodeWorker task to retrieve the source of the bitmap. + */ + public interface ImageWorkerTaskResource { + /** + * Opens a new InputStream that can be decoded as a bitmap by the + * BitmapFactory. + */ + public InputStream openImageInputStream(); + + /** + * Returns an InputStream that points to the beginning of the image + * resource. Implementations can either create a new InputStream or + * reset the existing one, depending on their implementation of + * openInputStream. If a new InputStream is returned, the one given as a + * parameter MUST be closed. + * + * @param input The input stream that was returned by openImageInputStream() + */ + public InputStream reopenImageInputStream(InputStream input); + + /** + * Returns a string that identifies the image resource. Example: file + * path of an image + */ + public String getImageLoaderCacheKey(); + } } diff --git a/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java b/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java index 745bc7079..4abb1a67d 100644 --- a/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java +++ b/src/de/danoeh/antennapod/asynctask/OpmlExportWorker.java @@ -1,11 +1,5 @@ package de.danoeh.antennapod.asynctask; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.util.Arrays; - import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -17,8 +11,13 @@ import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; import de.danoeh.antennapod.opml.OpmlWriter; import de.danoeh.antennapod.preferences.UserPreferences; -import de.danoeh.antennapod.util.LangUtils; import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.util.LangUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; /** Writes an OPML file into the export directory in the background. */ public class OpmlExportWorker extends AsyncTask<Void, Void, Void> { diff --git a/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java b/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java index 64e678086..038b8dcc5 100644 --- a/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java +++ b/src/de/danoeh/antennapod/asynctask/OpmlFeedQueuer.java @@ -1,8 +1,5 @@ package de.danoeh.antennapod.asynctask; -import java.util.Arrays; -import java.util.Date; - import android.annotation.SuppressLint; import android.app.ProgressDialog; import android.content.Context; @@ -14,6 +11,9 @@ import de.danoeh.antennapod.opml.OpmlElement; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; +import java.util.Arrays; +import java.util.Date; + /** Queues items for download in the background. */ public class OpmlFeedQueuer extends AsyncTask<Void, Void, Void> { private Context context; diff --git a/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java b/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java index 4816c25ab..13534fa64 100644 --- a/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java +++ b/src/de/danoeh/antennapod/asynctask/OpmlImportWorker.java @@ -1,11 +1,5 @@ package de.danoeh.antennapod.asynctask; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; - -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -14,10 +8,15 @@ import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.os.AsyncTask; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.opml.OpmlElement; import de.danoeh.antennapod.opml.OpmlReader; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; public class OpmlImportWorker extends AsyncTask<Void, Void, ArrayList<OpmlElement>> { @@ -38,7 +37,7 @@ public class OpmlImportWorker extends @Override protected ArrayList<OpmlElement> doInBackground(Void... params) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting background work"); if (mReader==null) { @@ -73,7 +72,7 @@ public class OpmlImportWorker extends } progDialog.dismiss(); if (exception != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "An error occured while trying to parse the opml document"); AlertDialog.Builder alert = new AlertDialog.Builder(context); diff --git a/src/de/danoeh/antennapod/dialog/ConfirmationDialog.java b/src/de/danoeh/antennapod/dialog/ConfirmationDialog.java index f4890ed53..df71fff77 100644 --- a/src/de/danoeh/antennapod/dialog/ConfirmationDialog.java +++ b/src/de/danoeh/antennapod/dialog/ConfirmationDialog.java @@ -4,7 +4,7 @@ import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; /** @@ -25,7 +25,7 @@ public abstract class ConfirmationDialog { } public void onCancelButtonPressed(DialogInterface dialog) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Dialog was cancelled"); dialog.dismiss(); } diff --git a/src/de/danoeh/antennapod/dialog/TimeDialog.java b/src/de/danoeh/antennapod/dialog/TimeDialog.java index fb5a72931..353a50adb 100644 --- a/src/de/danoeh/antennapod/dialog/TimeDialog.java +++ b/src/de/danoeh/antennapod/dialog/TimeDialog.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.dialog; -import java.util.concurrent.TimeUnit; - import android.app.Dialog; import android.content.Context; import android.os.Bundle; @@ -10,14 +8,12 @@ import android.text.TextWatcher; import android.util.Log; import android.view.View; import android.view.Window; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Spinner; -import android.widget.Toast; -import de.danoeh.antennapod.AppConfig; +import android.widget.*; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; +import java.util.concurrent.TimeUnit; + public abstract class TimeDialog extends Dialog { private static final String TAG = "TimeDialog"; @@ -108,11 +104,11 @@ public abstract class TimeDialog extends Dialog { private void checkInputLength(int length) { if (length > 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Length is larger than 0, enabling confirm button"); butConfirm.setEnabled(true); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Length is smaller than 0, disabling confirm button"); butConfirm.setEnabled(false); } diff --git a/src/de/danoeh/antennapod/dialog/VariableSpeedDialog.java b/src/de/danoeh/antennapod/dialog/VariableSpeedDialog.java index e6cbe37d1..b009e76a7 100644 --- a/src/de/danoeh/antennapod/dialog/VariableSpeedDialog.java +++ b/src/de/danoeh/antennapod/dialog/VariableSpeedDialog.java @@ -1,8 +1,5 @@ package de.danoeh.antennapod.dialog; -import java.util.Arrays; -import java.util.List; - import android.app.AlertDialog; import android.content.ActivityNotFoundException; import android.content.Context; @@ -12,6 +9,9 @@ import android.net.Uri; import de.danoeh.antennapod.R; import de.danoeh.antennapod.preferences.UserPreferences; +import java.util.Arrays; +import java.util.List; + public class VariableSpeedDialog { private VariableSpeedDialog() { } diff --git a/src/de/danoeh/antennapod/feed/Chapter.java b/src/de/danoeh/antennapod/feed/Chapter.java index ebf8ed44f..d6151ee9f 100644 --- a/src/de/danoeh/antennapod/feed/Chapter.java +++ b/src/de/danoeh/antennapod/feed/Chapter.java @@ -48,4 +48,8 @@ public abstract class Chapter extends FeedComponent { this.link = link; } + @Override + public String getHumanReadableIdentifier() { + return title; + } } diff --git a/src/de/danoeh/antennapod/feed/EventDistributor.java b/src/de/danoeh/antennapod/feed/EventDistributor.java index 56333da52..85a9b5727 100644 --- a/src/de/danoeh/antennapod/feed/EventDistributor.java +++ b/src/de/danoeh/antennapod/feed/EventDistributor.java @@ -1,14 +1,14 @@ package de.danoeh.antennapod.feed; +import android.os.Handler; +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; + import java.util.AbstractQueue; import java.util.Observable; import java.util.Observer; import java.util.concurrent.ConcurrentLinkedQueue; -import android.os.Handler; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; - /** * Notifies its observers about changes in the feed database. Observers can * register by retrieving an instance of this class and registering an @@ -67,7 +67,7 @@ public class EventDistributor extends Observable { private void processEventQueue() { Integer result = 0; - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Processing event queue. Number of events: " + events.size()); @@ -76,12 +76,12 @@ public class EventDistributor extends Observable { result |= current; } if (result != 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Notifying observers. Data: " + result); setChanged(); notifyObservers(result); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Event queue didn't contain any new events. Observers will not be notified."); } diff --git a/src/de/danoeh/antennapod/feed/Feed.java b/src/de/danoeh/antennapod/feed/Feed.java index 994446f43..9e423ff8b 100644 --- a/src/de/danoeh/antennapod/feed/Feed.java +++ b/src/de/danoeh/antennapod/feed/Feed.java @@ -1,18 +1,16 @@ package de.danoeh.antennapod.feed; import android.content.Context; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; - import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.storage.DBWriter; import de.danoeh.antennapod.util.EpisodeFilter; import de.danoeh.antennapod.util.flattr.FlattrStatus; import de.danoeh.antennapod.util.flattr.FlattrThing; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + /** * Data Object for a whole feed * @@ -125,6 +123,15 @@ public class Feed extends FeedFile implements FlattrThing { } /** + * This constructor is used for requesting a feed download (it must not be used for anything else!). It should be + * used if the title of the feed is already known. + */ + public Feed(String url, Date lastUpdate, String title, String username, String password) { + this(url, lastUpdate, title); + preferences = new FeedPreferences(0, true, username, password); + } + + /** * Returns the number of FeedItems where 'read' is false. If the 'display * only episodes' - preference is set to true, this method will only count * items with episodes. @@ -413,4 +420,12 @@ public class Feed extends FeedFile implements FlattrThing { public void savePreferences(Context context) { DBWriter.setFeedPreferences(context, preferences); } + + @Override + public void setId(long id) { + super.setId(id); + if (preferences != null) { + preferences.setFeedID(id); + } + } } diff --git a/src/de/danoeh/antennapod/feed/FeedComponent.java b/src/de/danoeh/antennapod/feed/FeedComponent.java index d23c8d7c8..66a2f9cc5 100644 --- a/src/de/danoeh/antennapod/feed/FeedComponent.java +++ b/src/de/danoeh/antennapod/feed/FeedComponent.java @@ -5,7 +5,7 @@ package de.danoeh.antennapod.feed; * @author daniel * */ -public class FeedComponent { +public abstract class FeedComponent { protected long id; @@ -39,7 +39,12 @@ public class FeedComponent { public boolean compareWithOther(FeedComponent other) { return false; } - - + + + /** + * Should return a non-null, human-readable String so that the item can be + * identified by the user. Can be title, download-url, etc. + */ + public abstract String getHumanReadableIdentifier(); }
\ No newline at end of file diff --git a/src/de/danoeh/antennapod/feed/FeedFile.java b/src/de/danoeh/antennapod/feed/FeedFile.java index 1d7a135d4..28a9b1e10 100644 --- a/src/de/danoeh/antennapod/feed/FeedFile.java +++ b/src/de/danoeh/antennapod/feed/FeedFile.java @@ -17,14 +17,8 @@ public abstract class FeedFile extends FeedComponent { } public FeedFile() { - this(null, null, false); - } - - /** - * Should return a non-null, human-readable String so that the item can be - * identified by the user. Can be title, download-url, etc. - */ - public abstract String getHumanReadableIdentifier(); + this(null, null, false); + } public abstract int getTypeAsInt(); diff --git a/src/de/danoeh/antennapod/feed/FeedImage.java b/src/de/danoeh/antennapod/feed/FeedImage.java index 3cc99d1c2..9c9170294 100644 --- a/src/de/danoeh/antennapod/feed/FeedImage.java +++ b/src/de/danoeh/antennapod/feed/FeedImage.java @@ -1,14 +1,13 @@ package de.danoeh.antennapod.feed; +import de.danoeh.antennapod.asynctask.ImageLoader; +import org.apache.commons.io.IOUtils; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; -import org.apache.commons.io.IOUtils; - -import de.danoeh.antennapod.asynctask.ImageLoader; - public class FeedImage extends FeedFile implements @@ -16,7 +15,7 @@ public class FeedImage extends FeedFile implements public static final int FEEDFILETYPE_FEEDIMAGE = 1; protected String title; - protected Feed feed; + protected FeedComponent owner; public FeedImage(String download_url, String title) { super(null, download_url, false); @@ -33,8 +32,8 @@ public class FeedImage extends FeedFile implements @Override public String getHumanReadableIdentifier() { - if (feed != null && feed.getTitle() != null) { - return feed.getTitle(); + if (owner != null && owner.getHumanReadableIdentifier() != null) { + return owner.getHumanReadableIdentifier(); } else { return download_url; } @@ -57,12 +56,12 @@ public class FeedImage extends FeedFile implements this.title = title; } - public Feed getFeed() { - return feed; + public FeedComponent getOwner() { + return owner; } - public void setFeed(Feed feed) { - this.feed = feed; + public void setOwner(FeedComponent owner) { + this.owner = owner; } @Override diff --git a/src/de/danoeh/antennapod/feed/FeedItem.java b/src/de/danoeh/antennapod/feed/FeedItem.java index f63b5beb4..921a03bff 100644 --- a/src/de/danoeh/antennapod/feed/FeedItem.java +++ b/src/de/danoeh/antennapod/feed/FeedItem.java @@ -1,11 +1,5 @@ package de.danoeh.antennapod.feed; -import java.io.InputStream; -import java.lang.ref.SoftReference; -import java.util.Date; -import java.util.List; -import java.util.concurrent.Callable; - import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.storage.DBReader; @@ -13,6 +7,11 @@ import de.danoeh.antennapod.util.ShownotesProvider; import de.danoeh.antennapod.util.flattr.FlattrStatus; import de.danoeh.antennapod.util.flattr.FlattrThing; +import java.io.InputStream; +import java.util.Date; +import java.util.List; +import java.util.concurrent.Callable; + /** * Data Object for a XML message * @@ -44,17 +43,18 @@ public class FeedItem extends FeedComponent implements private boolean read; private String paymentLink; - private FlattrStatus flattrStatus; + private FlattrStatus flattrStatus; private List<Chapter> chapters; + private FeedImage image; public FeedItem() { this.read = true; - this.flattrStatus = new FlattrStatus(); + this.flattrStatus = new FlattrStatus(); } /** * This constructor should be used for creating test objects. - * */ + */ public FeedItem(long id, String title, String itemIdentifier, String link, Date pubDate, boolean read, Feed feed) { this.id = id; this.title = title; @@ -63,7 +63,7 @@ public class FeedItem extends FeedComponent implements this.pubDate = (pubDate != null) ? (Date) pubDate.clone() : null; this.read = read; this.feed = feed; - this.flattrStatus = new FlattrStatus(); + this.flattrStatus = new FlattrStatus(); } public void updateFromOther(FeedItem other) { @@ -98,6 +98,9 @@ public class FeedItem extends FeedComponent implements chapters = other.chapters; } } + if (image == null) { + image = other.image; + } } /** @@ -164,7 +167,7 @@ public class FeedItem extends FeedComponent implements * Sets the media object of this FeedItem. If the given * FeedMedia object is not null, it's 'item'-attribute value * will also be set to this item. - * */ + */ public void setMedia(FeedMedia media) { this.media = media; if (media != null && media.getItem() != this) { @@ -200,15 +203,15 @@ public class FeedItem extends FeedComponent implements this.contentEncoded = contentEncoded; } - public void setFlattrStatus(FlattrStatus status) { - this.flattrStatus = status; - } + public void setFlattrStatus(FlattrStatus status) { + this.flattrStatus = status; + } - public FlattrStatus getFlattrStatus() { - return flattrStatus; - } + public FlattrStatus getFlattrStatus() { + return flattrStatus; + } - public String getPaymentLink() { + public String getPaymentLink() { return paymentLink; } @@ -277,10 +280,11 @@ public class FeedItem extends FeedComponent implements @Override public InputStream openImageInputStream() { InputStream out = null; - if (hasMedia()) { + if (hasItemImage()) { + out = image.openImageInputStream(); + } else if (hasMedia()) { out = media.openImageInputStream(); - } - if (out == null && feed.getImage() != null) { + } else if (feed.getImage() != null) { out = feed.getImage().openImageInputStream(); } return out; @@ -289,10 +293,11 @@ public class FeedItem extends FeedComponent implements @Override public InputStream reopenImageInputStream(InputStream input) { InputStream out = null; - if (hasMedia()) { + if (hasItemImage()) { + out = image.reopenImageInputStream(input); + } else if (hasMedia()) { out = media.reopenImageInputStream(input); - } - if (out == null && feed.getImage() != null) { + } else if (feed.getImage() != null) { out = feed.getImage().reopenImageInputStream(input); } return out; @@ -301,10 +306,11 @@ public class FeedItem extends FeedComponent implements @Override public String getImageLoaderCacheKey() { String out = null; - if (hasMedia()) { + if (hasItemImage()) { + out = image.getImageLoaderCacheKey(); + } else if (hasMedia()) { out = media.getImageLoaderCacheKey(); - } - if (out == null && feed.getImage() != null) { + } else if (feed.getImage() != null) { out = feed.getImage().getImageLoaderCacheKey(); } return out; @@ -318,4 +324,30 @@ public class FeedItem extends FeedComponent implements this.feedId = feedId; } + /** + * Returns the image of this item or the image of the feed if this item does + * not have its own image. + */ + public FeedImage getImage() { + return (hasItemImage()) ? image : feed.getImage(); + } + + public void setImage(FeedImage image) { + this.image = image; + if (image != null) { + image.setOwner(this); + } + } + + /** + * Returns true if this FeedItem has its own image, false otherwise. + */ + public boolean hasItemImage() { + return image != null; + } + + @Override + public String getHumanReadableIdentifier() { + return title; + } } diff --git a/src/de/danoeh/antennapod/feed/FeedMedia.java b/src/de/danoeh/antennapod/feed/FeedMedia.java index fe2c3d17e..f38e92398 100644 --- a/src/de/danoeh/antennapod/feed/FeedMedia.java +++ b/src/de/danoeh/antennapod/feed/FeedMedia.java @@ -4,8 +4,6 @@ import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.preferences.PlaybackPreferences; import de.danoeh.antennapod.storage.DBReader; @@ -205,8 +203,8 @@ public class FeedMedia extends FeedFile implements Playable { } public FeedImage getImage() { - if (item != null && item.getFeed() != null) { - return item.getFeed().getImage(); + if (item != null) { + return (item.hasItemImage()) ? item.getImage() : item.getFeed().getImage(); } return null; } @@ -385,8 +383,13 @@ public class FeedMedia extends FeedFile implements Playable { @Override public InputStream openImageInputStream() { - InputStream out = new Playable.DefaultPlayableImageLoader(this) - .openImageInputStream(); + InputStream out; + if (item.hasItemImage()) { + out = item.openImageInputStream(); + } else { + out = new Playable.DefaultPlayableImageLoader(this) + .openImageInputStream(); + } if (out == null) { if (item.getFeed().getImage() != null) { return item.getFeed().getImage().openImageInputStream(); @@ -397,8 +400,13 @@ public class FeedMedia extends FeedFile implements Playable { @Override public String getImageLoaderCacheKey() { - String out = new Playable.DefaultPlayableImageLoader(this) - .getImageLoaderCacheKey(); + String out; + if (item.hasItemImage()) { + out = item.getImageLoaderCacheKey(); + } else { + out = new Playable.DefaultPlayableImageLoader(this) + .getImageLoaderCacheKey(); + } if (out == null) { if (item.getFeed().getImage() != null) { return item.getFeed().getImage().getImageLoaderCacheKey(); @@ -410,7 +418,7 @@ public class FeedMedia extends FeedFile implements Playable { @Override public InputStream reopenImageInputStream(InputStream input) { if (input instanceof FileInputStream) { - return item.getFeed().getImage().reopenImageInputStream(input); + return item.getImage().reopenImageInputStream(input); } else { return new Playable.DefaultPlayableImageLoader(this) .reopenImageInputStream(input); diff --git a/src/de/danoeh/antennapod/feed/FeedPreferences.java b/src/de/danoeh/antennapod/feed/FeedPreferences.java index a63c1d52b..29bc5ef0c 100644 --- a/src/de/danoeh/antennapod/feed/FeedPreferences.java +++ b/src/de/danoeh/antennapod/feed/FeedPreferences.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.feed; import android.content.Context; - import de.danoeh.antennapod.storage.DBWriter; +import org.apache.commons.lang3.StringUtils; /** * Contains preferences for a single feed. @@ -11,10 +11,44 @@ public class FeedPreferences { private long feedID; private boolean autoDownload; + private String username; + private String password; - public FeedPreferences(long feedID, boolean autoDownload) { + public FeedPreferences(long feedID, boolean autoDownload, String username, String password) { this.feedID = feedID; this.autoDownload = autoDownload; + this.username = username; + this.password = password; + } + + + /** + * Compare another FeedPreferences with this one. The feedID and autoDownload attribute are excluded from the + * comparison. + * + * @return True if the two objects are different. + */ + public boolean compareWithOther(FeedPreferences other) { + if (other == null) + return true; + if (!StringUtils.equals(username, other.username)) { + return true; + } + if (!StringUtils.equals(password, other.password)) { + return true; + } + return false; + } + + /** + * Update this FeedPreferences object from another one. The feedID and autoDownload attributes are excluded + * from the update. + */ + public void updateFromOther(FeedPreferences other) { + if (other == null) + return; + this.username = other.username; + this.password = other.password; } public long getFeedID() { @@ -36,4 +70,20 @@ public class FeedPreferences { public void save(Context context) { DBWriter.setFeedPreferences(context, this); } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } } diff --git a/src/de/danoeh/antennapod/feed/VorbisCommentChapter.java b/src/de/danoeh/antennapod/feed/VorbisCommentChapter.java index 544e762d3..59844ae1f 100644 --- a/src/de/danoeh/antennapod/feed/VorbisCommentChapter.java +++ b/src/de/danoeh/antennapod/feed/VorbisCommentChapter.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.feed; -import java.util.concurrent.TimeUnit; - import de.danoeh.antennapod.util.vorbiscommentreader.VorbisCommentReaderException; +import java.util.concurrent.TimeUnit; + public class VorbisCommentChapter extends Chapter { public static final int CHAPTERTYPE_VORBISCOMMENT_CHAPTER = 3; diff --git a/src/de/danoeh/antennapod/fragment/CoverFragment.java b/src/de/danoeh/antennapod/fragment/CoverFragment.java index 791315719..0e1fe35e0 100644 --- a/src/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/src/de/danoeh/antennapod/fragment/CoverFragment.java @@ -7,8 +7,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment; import de.danoeh.antennapod.asynctask.ImageLoader; @@ -74,11 +73,11 @@ public class CoverFragment extends Fragment implements @Override public void onStart() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "On Start"); super.onStart(); if (media != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading media info"); loadMediaInfo(); } else { diff --git a/src/de/danoeh/antennapod/fragment/EpisodesFragment.java b/src/de/danoeh/antennapod/fragment/EpisodesFragment.java index 6b228662f..3c79a8c10 100644 --- a/src/de/danoeh/antennapod/fragment/EpisodesFragment.java +++ b/src/de/danoeh/antennapod/fragment/EpisodesFragment.java @@ -10,8 +10,7 @@ import android.view.*; import android.view.ContextMenu.ContextMenuInfo; import android.widget.ExpandableListView; import android.widget.ExpandableListView.OnChildClickListener; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.ItemviewActivity; import de.danoeh.antennapod.activity.OrganizeQueueActivity; @@ -156,7 +155,7 @@ public class EpisodesFragment extends Fragment { @Override protected Void doInBackground(Void... voids) { - if (AppConfig.DEBUG) Log.d(TAG, "Starting to load list data"); + if (BuildConfig.DEBUG) Log.d(TAG, "Starting to load list data"); Context context = EpisodesFragment.this.getActivity(); if (context != null) { queueRef = DBReader.getQueue(context); @@ -169,7 +168,7 @@ public class EpisodesFragment extends Fragment { protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); if (queueRef != null && unreadItemsRef != null) { - if (AppConfig.DEBUG) Log.d(TAG, "Done loading list data"); + if (BuildConfig.DEBUG) Log.d(TAG, "Done loading list data"); queue = queueRef; unreadItems = unreadItemsRef; if (adapter != null) { @@ -193,7 +192,7 @@ public class EpisodesFragment extends Fragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((EVENTS & arg) != 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received contentUpdate Intent."); loadData(); } diff --git a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java index 56e6ee4b8..47cd3f244 100644 --- a/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java +++ b/src/de/danoeh/antennapod/fragment/ExternalPlayerFragment.java @@ -10,8 +10,7 @@ import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.service.playback.PlaybackService; @@ -57,7 +56,7 @@ public class ExternalPlayerFragment extends Fragment { @Override public void onClick(View v) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "layoutInfo was clicked"); if (controller.getMedia() != null) { @@ -196,7 +195,7 @@ public class ExternalPlayerFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Fragment is about to be destroyed"); if (controller != null) { controller.release(); @@ -212,7 +211,7 @@ public class ExternalPlayerFragment extends Fragment { } private boolean loadMediaInfo() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading media info"); if (controller.serviceAvailable()) { Playable media = controller.getMedia(); diff --git a/src/de/danoeh/antennapod/fragment/FeedlistFragment.java b/src/de/danoeh/antennapod/fragment/FeedlistFragment.java index d0e07b194..0d2f0d079 100644 --- a/src/de/danoeh/antennapod/fragment/FeedlistFragment.java +++ b/src/de/danoeh/antennapod/fragment/FeedlistFragment.java @@ -5,7 +5,6 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v7.app.ActionBarActivity; @@ -13,7 +12,7 @@ import android.support.v7.view.ActionMode; import android.util.Log; import android.view.*; import android.widget.*; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.FeedItemlistActivity; import de.danoeh.antennapod.adapter.FeedlistAdapter; @@ -85,7 +84,7 @@ public class FeedlistFragment extends Fragment implements @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating"); fla = new FeedlistAdapter(getActivity(), itemAccess); loadFeeds(); @@ -143,14 +142,14 @@ public class FeedlistFragment extends Fragment implements listView.setOnItemLongClickListener(this); listView.setAdapter(fla); listView.setEmptyView(emptyView); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Using ListView"); } else { gridView.setOnItemClickListener(this); gridView.setOnItemLongClickListener(this); gridView.setAdapter(fla); gridView.setEmptyView(emptyView); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Using GridView"); } setEmptyViewIfListIsEmpty(); @@ -159,7 +158,7 @@ public class FeedlistFragment extends Fragment implements @Override public void onResume() { super.onResume(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Resuming"); EventDistributor.getInstance().register(contentUpdate); } @@ -183,7 +182,7 @@ public class FeedlistFragment extends Fragment implements @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((EVENTS & arg) != 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received contentUpdate Intent."); loadFeeds(); } @@ -266,7 +265,7 @@ public class FeedlistFragment extends Fragment implements int position, long id) { Feed selection = fla.getItem(position); if (selection != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Selected Feed with title " + selection.getTitle()); if (mActionMode != null) { mActionMode.finish(); diff --git a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index c996f497e..48c544457 100644 --- a/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -1,39 +1,32 @@ package de.danoeh.antennapod.fragment; -import android.content.*; -import android.support.v4.app.Fragment; -import android.support.v7.app.ActionBarActivity; -import de.danoeh.antennapod.feed.FeedItem; -import de.danoeh.antennapod.storage.DBReader; -import de.danoeh.antennapod.util.ShownotesProvider; -import org.apache.commons.lang3.StringEscapeUtils; - import android.annotation.SuppressLint; import android.app.Activity; +import android.content.*; import android.content.res.TypedArray; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v7.app.ActionBarActivity; import android.util.Log; import android.util.TypedValue; -import android.view.ContextMenu; +import android.view.*; import android.view.ContextMenu.ContextMenuInfo; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; import android.webkit.WebSettings.LayoutAlgorithm; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Toast; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.preferences.UserPreferences; +import de.danoeh.antennapod.storage.DBReader; import de.danoeh.antennapod.util.ShareUtils; +import de.danoeh.antennapod.util.ShownotesProvider; import de.danoeh.antennapod.util.playback.Playable; +import org.apache.commons.lang3.StringEscapeUtils; import java.util.concurrent.Callable; @@ -93,7 +86,7 @@ public class ItemDescriptionFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating view"); webvDescription = new WebView(getActivity()); if (UserPreferences.getTheme() == R.style.Theme_AntennaPod_Dark) { @@ -126,7 +119,7 @@ public class ItemDescriptionFragment extends Fragment { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Page finished"); // Restoring the scroll position might not always work view.postDelayed(new Runnable() { @@ -153,14 +146,14 @@ public class ItemDescriptionFragment extends Fragment { @Override public void onAttach(Activity activity) { super.onAttach(activity); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Fragment attached"); } @Override public void onDetach() { super.onDetach(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Fragment detached"); if (webViewLoader != null) { webViewLoader.cancel(true); @@ -170,7 +163,7 @@ public class ItemDescriptionFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Fragment destroyed"); if (webViewLoader != null) { webViewLoader.cancel(true); @@ -181,7 +174,7 @@ public class ItemDescriptionFragment extends Fragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating fragment"); Bundle args = getArguments(); saveState = args.getBoolean(ARG_SAVE_STATE, false); @@ -258,7 +251,7 @@ public class ItemDescriptionFragment extends Fragment { WebView.HitTestResult r = webvDescription.getHitTestResult(); if (r != null && r.getType() == WebView.HitTestResult.SRC_ANCHOR_TYPE) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Link of webview was long-pressed. Extra: " + r.getExtra()); @@ -352,7 +345,7 @@ public class ItemDescriptionFragment extends Fragment { ((ActionBarActivity) getActivity()) .setSupportProgressBarIndeterminateVisibility(false); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Webview loaded"); webViewLoader = null; } @@ -368,7 +361,7 @@ public class ItemDescriptionFragment extends Fragment { @Override protected Void doInBackground(Void... params) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading Webview"); try { Callable<String> shownotesLoadTask = shownotesProvider.loadShownotes(); @@ -407,13 +400,13 @@ public class ItemDescriptionFragment extends Fragment { private void savePreference() { if (saveState) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Saving preferences"); SharedPreferences prefs = getActivity().getSharedPreferences(PREF, Activity.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); if (media != null && webvDescription != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Saving scroll position: " + webvDescription.getScrollY()); @@ -421,7 +414,7 @@ public class ItemDescriptionFragment extends Fragment { editor.putString(PREF_PLAYABLE_ID, media.getIdentifier() .toString()); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "savePreferences was called while media or webview was null"); editor.putInt(PREF_SCROLL_Y, -1); @@ -433,7 +426,7 @@ public class ItemDescriptionFragment extends Fragment { private boolean restoreFromPreference() { if (saveState) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Restoring from preferences"); Activity activity = getActivity(); if (activity != null) { @@ -444,7 +437,7 @@ public class ItemDescriptionFragment extends Fragment { if (scrollY != -1 && media != null && id.equals(media.getIdentifier().toString()) && webvDescription != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Restored scroll Position: " + scrollY); webvDescription.scrollTo(webvDescription.getScrollX(), scrollY); diff --git a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java index 436210a70..e5845dd76 100644 --- a/src/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/src/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -8,17 +8,11 @@ import android.os.Bundle; import android.support.v4.app.ListFragment; import android.support.v7.app.ActionBarActivity; import android.util.Log; -import android.view.ContextMenu; +import android.view.*; import android.view.ContextMenu.ContextMenuInfo; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.View; -import android.view.ViewGroup; import android.widget.ListView; - import android.widget.TextView; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.ItemviewActivity; import de.danoeh.antennapod.adapter.ActionButtonCallback; @@ -34,7 +28,6 @@ import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.QueueAccess; import de.danoeh.antennapod.util.menuhandler.FeedItemMenuHandler; -import java.util.Iterator; import java.util.List; /** Displays a list of FeedItems. */ @@ -229,7 +222,7 @@ public class ItemlistFragment extends ListFragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((EVENTS & arg) != 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received contentUpdate Intent."); if ((EventDistributor.DOWNLOAD_QUEUED & arg) != 0) { updateProgressBarVisibility(); diff --git a/src/de/danoeh/antennapod/fragment/MiroGuideChannellistFragment.java b/src/de/danoeh/antennapod/fragment/MiroGuideChannellistFragment.java index c6901ad17..53910b673 100644 --- a/src/de/danoeh/antennapod/fragment/MiroGuideChannellistFragment.java +++ b/src/de/danoeh/antennapod/fragment/MiroGuideChannellistFragment.java @@ -1,8 +1,5 @@ package de.danoeh.antennapod.fragment; -import java.util.ArrayList; -import java.util.List; - import android.annotation.SuppressLint; import android.app.AlertDialog; import android.content.Context; @@ -17,8 +14,7 @@ import android.view.View; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ListView; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.MiroGuideChannelViewActivity; import de.danoeh.antennapod.adapter.MiroGuideChannelListAdapter; @@ -26,6 +22,9 @@ import de.danoeh.antennapod.miroguide.conn.MiroGuideException; import de.danoeh.antennapod.miroguide.conn.MiroGuideService; import de.danoeh.antennapod.miroguide.model.MiroGuideChannel; +import java.util.ArrayList; +import java.util.List; + /** * Displays a list of MiroGuideChannel objects that were results of a certain * MiroGuideService query. If the user reaches the bottom of the list, more @@ -139,7 +138,7 @@ public class MiroGuideChannellistFragment extends ListFragment { int visibleItemCount, int totalItemCount) { int lastVisibleItem = firstVisibleItem + visibleItemCount; if (lastVisibleItem == totalItemCount) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) loadChannels(); } } @@ -177,13 +176,13 @@ public class MiroGuideChannellistFragment extends ListFragment { @Override protected void onCancelled() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Channel loader was cancelled"); } @Override protected void onPostExecute(List<MiroGuideChannel> result) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Channel loading finished"); if (exception == null) { getListView().removeFooterView(footer); @@ -195,13 +194,13 @@ public class MiroGuideChannellistFragment extends ListFragment { // check if fragment should not send any more // queries if (result.size() < CHANNELS_PER_QUERY) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Query result was less than requested number of channels. Stopping to send any more queries"); stopLoading = true; } if (offset >= MAX_CHANNELS) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Maximum number of feeds has been reached. Stopping to send any more queries"); stopLoading = true; @@ -236,7 +235,7 @@ public class MiroGuideChannellistFragment extends ListFragment { @Override protected List<MiroGuideChannel> doInBackground( Void... params) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Background channel loader started"); MiroGuideService service = new MiroGuideService(); try { @@ -260,7 +259,7 @@ public class MiroGuideChannellistFragment extends ListFragment { } } } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Channels are already being loaded"); } } diff --git a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java index d20cb63c4..d6524853f 100644 --- a/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java +++ b/src/de/danoeh/antennapod/fragment/PlaybackHistoryFragment.java @@ -4,13 +4,12 @@ import android.content.Context; import android.os.AsyncTask; import android.os.Bundle; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.adapter.InternalFeedItemlistAdapter; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.storage.DBReader; -import java.util.Iterator; import java.util.List; public class PlaybackHistoryFragment extends ItemlistFragment { @@ -64,7 +63,7 @@ public class PlaybackHistoryFragment extends ItemlistFragment { @Override public void update(EventDistributor eventDistributor, Integer arg) { if ((EventDistributor.PLAYBACK_HISTORY_UPDATE & arg) != 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received content update"); loadData(); } diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java index 3014d28cc..4164429b2 100644 --- a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java +++ b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastListFragment.java @@ -10,7 +10,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.*; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.DefaultOnlineFeedViewActivity; import de.danoeh.antennapod.activity.OnlineFeedViewActivity; @@ -60,7 +60,7 @@ public abstract class PodcastListFragment extends Fragment { } protected void onPodcastSelected(GpodnetPodcast selection) { - if (AppConfig.DEBUG) Log.d(TAG, "Selected podcast: " + selection.toString()); + if (BuildConfig.DEBUG) Log.d(TAG, "Selected podcast: " + selection.toString()); Intent intent = new Intent(getActivity(), DefaultOnlineFeedViewActivity.class); intent.putExtra(OnlineFeedViewActivity.ARG_FEEDURL, selection.getUrl()); intent.putExtra(DefaultOnlineFeedViewActivity.ARG_TITLE, getString(R.string.gpodnet_main_label)); diff --git a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java index 7007d0b9a..5717a74e7 100644 --- a/src/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java +++ b/src/de/danoeh/antennapod/fragment/gpodnet/PodcastTopListFragment.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.fragment.gpodnet; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; import de.danoeh.antennapod.gpoddernet.GpodnetService; import de.danoeh.antennapod.gpoddernet.GpodnetServiceException; import de.danoeh.antennapod.gpoddernet.model.GpodnetPodcast; diff --git a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java b/src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java index ee1a3ea21..b4c06c340 100644 --- a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java +++ b/src/de/danoeh/antennapod/miroguide/conn/MiroGuideConnector.java @@ -1,10 +1,7 @@ package de.danoeh.antennapod.miroguide.conn; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - +import android.net.Uri; +import de.danoeh.antennapod.util.LangUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; @@ -14,9 +11,9 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import android.net.Uri; - -import de.danoeh.antennapod.util.LangUtils; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; /** Executes HTTP requests and returns the results. */ public class MiroGuideConnector { diff --git a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java b/src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java index 5cb137574..bdb4ec5dd 100644 --- a/src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java +++ b/src/de/danoeh/antennapod/miroguide/conn/MiroGuideService.java @@ -1,5 +1,11 @@ package de.danoeh.antennapod.miroguide.conn; +import de.danoeh.antennapod.miroguide.model.MiroGuideChannel; +import de.danoeh.antennapod.miroguide.model.MiroGuideItem; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -7,13 +13,6 @@ import java.util.Date; import java.util.List; import java.util.Locale; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import de.danoeh.antennapod.miroguide.model.MiroGuideChannel; -import de.danoeh.antennapod.miroguide.model.MiroGuideItem; - /** Provides methods to communicate with the Miroguide API on an abstract level. */ public class MiroGuideService { diff --git a/src/de/danoeh/antennapod/opml/OpmlReader.java b/src/de/danoeh/antennapod/opml/OpmlReader.java index 61a00742c..19a980dee 100644 --- a/src/de/danoeh/antennapod/opml/OpmlReader.java +++ b/src/de/danoeh/antennapod/opml/OpmlReader.java @@ -1,15 +1,14 @@ package de.danoeh.antennapod.opml; -import java.io.IOException; -import java.io.Reader; -import java.util.ArrayList; - +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; /** Reads OPML documents. */ public class OpmlReader { @@ -38,16 +37,16 @@ public class OpmlReader { while (eventType != XmlPullParser.END_DOCUMENT) { switch (eventType) { case XmlPullParser.START_DOCUMENT: - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Reached beginning of document"); break; case XmlPullParser.START_TAG: if (xpp.getName().equals(OpmlSymbols.OPML)) { isInOpml = true; - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Reached beginning of OPML tree."); } else if (isInOpml && xpp.getName().equals(OpmlSymbols.OUTLINE)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Found new Opml element"); OpmlElement element = new OpmlElement(); @@ -69,7 +68,7 @@ public class OpmlReader { } elementList.add(element); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Skipping element because of missing xml url"); } @@ -79,7 +78,7 @@ public class OpmlReader { eventType = xpp.next(); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Parsing finished."); return elementList; diff --git a/src/de/danoeh/antennapod/opml/OpmlWriter.java b/src/de/danoeh/antennapod/opml/OpmlWriter.java index 955c4f2f1..405a5e35a 100644 --- a/src/de/danoeh/antennapod/opml/OpmlWriter.java +++ b/src/de/danoeh/antennapod/opml/OpmlWriter.java @@ -1,15 +1,14 @@ package de.danoeh.antennapod.opml; -import java.io.IOException; -import java.io.Writer; -import java.util.List; - -import org.xmlpull.v1.XmlSerializer; - import android.util.Log; import android.util.Xml; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.Feed; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; /** Writes OPML documents. */ public class OpmlWriter { @@ -28,7 +27,7 @@ public class OpmlWriter { */ public void writeDocument(List<Feed> feeds, Writer writer) throws IllegalArgumentException, IllegalStateException, IOException { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting to write document"); XmlSerializer xs = Xml.newSerializer(); xs.setOutput(writer); @@ -60,7 +59,7 @@ public class OpmlWriter { xs.endTag(null, OpmlSymbols.BODY); xs.endTag(null, OpmlSymbols.OPML); xs.endDocument(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Finished writing document"); } } diff --git a/src/de/danoeh/antennapod/preferences/GpodnetPreferences.java b/src/de/danoeh/antennapod/preferences/GpodnetPreferences.java index 0130a4a87..bdfe297a6 100644 --- a/src/de/danoeh/antennapod/preferences/GpodnetPreferences.java +++ b/src/de/danoeh/antennapod/preferences/GpodnetPreferences.java @@ -3,7 +3,7 @@ package de.danoeh.antennapod.preferences; import android.content.Context; import android.content.SharedPreferences; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.gpoddernet.GpodnetService; import de.danoeh.antennapod.service.GpodnetSyncService; @@ -206,7 +206,7 @@ public class GpodnetPreferences { } public static synchronized void logout() { - if (AppConfig.DEBUG) Log.d(TAG, "Logout: Clearing preferences"); + if (BuildConfig.DEBUG) Log.d(TAG, "Logout: Clearing preferences"); setUsername(null); setPassword(null); setDeviceID(null); diff --git a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java index 9ae0f8f2f..80e0768dd 100644 --- a/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java +++ b/src/de/danoeh/antennapod/preferences/PlaybackPreferences.java @@ -4,7 +4,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; /** * Provides access to preferences set by the playback service. A private @@ -64,7 +64,7 @@ public class PlaybackPreferences implements * if context is null * */ public static void createInstance(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating new instance of UserPreferences"); if (context == null) throw new IllegalArgumentException("Context must not be null"); diff --git a/src/de/danoeh/antennapod/preferences/UserPreferences.java b/src/de/danoeh/antennapod/preferences/UserPreferences.java index 2b4b66362..3662b646e 100644 --- a/src/de/danoeh/antennapod/preferences/UserPreferences.java +++ b/src/de/danoeh/antennapod/preferences/UserPreferences.java @@ -1,16 +1,5 @@ package de.danoeh.antennapod.preferences; -import java.io.File; -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import de.danoeh.antennapod.gpoddernet.GpodnetService; -import org.apache.commons.lang3.StringUtils; -import org.json.JSONArray; -import org.json.JSONException; - import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; @@ -18,10 +7,19 @@ import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.OpmlImportFromPathActivity; import de.danoeh.antennapod.receiver.FeedUpdateReceiver; +import org.apache.commons.lang3.StringUtils; +import org.json.JSONArray; +import org.json.JSONException; + +import java.io.File; +import java.io.IOException; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.TimeUnit; /** * Provides access to preferences set by the user in the settings screen. A @@ -89,7 +87,7 @@ public class UserPreferences implements * if context is null * */ public static void createInstance(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating new instance of UserPreferences"); if (context == null) throw new IllegalArgumentException("Context must not be null"); @@ -286,7 +284,7 @@ public class UserPreferences implements @Override public void onSharedPreferenceChanged(SharedPreferences sp, String key) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Registered change of user preferences. Key: " + key); if (key.equals(PREF_DOWNLOAD_MEDIA_ON_WIFI_ONLY)) { @@ -392,7 +390,7 @@ public class UserPreferences implements .getDefaultSharedPreferences(context.getApplicationContext()); String strDir = prefs.getString(PREF_DATA_FOLDER, null); if (strDir == null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Using default data folder"); return context.getExternalFilesDir(type); } else { @@ -437,7 +435,7 @@ public class UserPreferences implements } public static void setDataFolder(String dir) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Result from DirectoryChooser: " + dir); instanceAvailable(); SharedPreferences prefs = PreferenceManager @@ -459,7 +457,7 @@ public class UserPreferences implements Log.e(TAG, "Could not create .nomedia file"); e.printStackTrace(); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, ".nomedia file created"); } } @@ -473,15 +471,15 @@ public class UserPreferences implements OpmlImportFromPathActivity.IMPORT_DIR); if (importDir != null) { if (importDir.exists()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Import directory already exists"); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating import directory"); importDir.mkdir(); } } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Could not access external storage."); } } @@ -495,7 +493,7 @@ public class UserPreferences implements * */ public static void restartUpdateAlarm(long millis) { instanceAvailable(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Restarting update alarm. New value: " + millis); AlarmManager alarmManager = (AlarmManager) instance.context .getSystemService(Context.ALARM_SERVICE); @@ -506,10 +504,10 @@ public class UserPreferences implements if (millis != 0) { alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, millis, millis, updateIntent); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Changed alarm to new interval"); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Automatic update was deactivated"); } } diff --git a/src/de/danoeh/antennapod/receiver/AlarmUpdateReceiver.java b/src/de/danoeh/antennapod/receiver/AlarmUpdateReceiver.java index 63a03b9e6..7b8879f21 100644 --- a/src/de/danoeh/antennapod/receiver/AlarmUpdateReceiver.java +++ b/src/de/danoeh/antennapod/receiver/AlarmUpdateReceiver.java @@ -4,7 +4,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.preferences.UserPreferences; /** Listens for events that make it necessary to reset the update alarm. */ @@ -13,13 +13,13 @@ public class AlarmUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received intent"); if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Resetting update alarm after reboot"); } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Resetting update alarm after app upgrade"); } diff --git a/src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java b/src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java index c1dd30be7..31c053386 100644 --- a/src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java +++ b/src/de/danoeh/antennapod/receiver/ConnectivityActionReceiver.java @@ -6,7 +6,7 @@ import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.storage.DBTasks; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.NetworkUtils; @@ -17,11 +17,11 @@ public class ConnectivityActionReceiver extends BroadcastReceiver { @Override public void onReceive(final Context context, Intent intent) { if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received intent"); if (NetworkUtils.autodownloadNetworkAvailable(context)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "auto-dl network available, starting auto-download"); DBTasks.autodownloadUndownloadedItems(context); @@ -31,7 +31,7 @@ public class ConnectivityActionReceiver extends BroadcastReceiver { .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo ni = cm.getActiveNetworkInfo(); if (ni == null || ni.getType() != ConnectivityManager.TYPE_WIFI) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.i(TAG, "Device is no longer connected to Wi-Fi. Cancelling ongoing downloads"); DownloadRequester.getInstance().cancelAllDownloads(context); diff --git a/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java b/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java index fdbaa97f0..a7482fbf4 100644 --- a/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java +++ b/src/de/danoeh/antennapod/receiver/FeedUpdateReceiver.java @@ -6,7 +6,7 @@ import android.content.Intent; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.storage.DBTasks; @@ -18,13 +18,13 @@ public class FeedUpdateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(ACTION_REFRESH_FEEDS)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received intent"); boolean mobileUpdate = UserPreferences.isAllowMobileUpdate(); if (mobileUpdate || connectedToWifi(context)) { DBTasks.refreshExpiredFeeds(context); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Blocking automatic update: no wifi available / no mobile updates allowed"); } diff --git a/src/de/danoeh/antennapod/receiver/MediaButtonReceiver.java b/src/de/danoeh/antennapod/receiver/MediaButtonReceiver.java index a53ad486a..1edebd275 100644 --- a/src/de/danoeh/antennapod/receiver/MediaButtonReceiver.java +++ b/src/de/danoeh/antennapod/receiver/MediaButtonReceiver.java @@ -5,7 +5,7 @@ import android.content.Context; import android.content.Intent; import android.util.Log; import android.view.KeyEvent; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.service.playback.PlaybackService; /** Receives media button events. */ @@ -17,7 +17,7 @@ public class MediaButtonReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (AppConfig.DEBUG) Log.d(TAG, "Received intent"); + if (BuildConfig.DEBUG) Log.d(TAG, "Received intent"); KeyEvent event = (KeyEvent) intent.getExtras().get( Intent.EXTRA_KEY_EVENT); if (event.getAction() == KeyEvent.ACTION_DOWN) { diff --git a/src/de/danoeh/antennapod/receiver/PlayerWidget.java b/src/de/danoeh/antennapod/receiver/PlayerWidget.java index 25bb53475..5748ced3b 100644 --- a/src/de/danoeh/antennapod/receiver/PlayerWidget.java +++ b/src/de/danoeh/antennapod/receiver/PlayerWidget.java @@ -5,7 +5,7 @@ import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.service.playback.PlayerWidgetService; public class PlayerWidget extends AppWidgetProvider { @@ -26,7 +26,7 @@ public class PlayerWidget extends AppWidgetProvider { @Override public void onEnabled(Context context) { super.onEnabled(context); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Widget enabled"); } diff --git a/src/de/danoeh/antennapod/receiver/SPAReceiver.java b/src/de/danoeh/antennapod/receiver/SPAReceiver.java new file mode 100644 index 000000000..b0430d170 --- /dev/null +++ b/src/de/danoeh/antennapod/receiver/SPAReceiver.java @@ -0,0 +1,55 @@ +package de.danoeh.antennapod.receiver; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.util.Log; +import android.widget.Toast; +import de.danoeh.antennapod.BuildConfig; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.feed.Feed; +import de.danoeh.antennapod.storage.DownloadRequestException; +import de.danoeh.antennapod.storage.DownloadRequester; +import org.apache.commons.lang3.StringUtils; + +import java.util.Arrays; +import java.util.Date; + +/** + * Receives intents from AntennaPod Single Purpose apps + */ +public class SPAReceiver extends BroadcastReceiver{ + private static final String TAG = "SPAReceiver"; + + public static final String ACTION_SP_APPS_QUERY_FEEDS = "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS"; + public static final String ACTION_SP_APPS_QUERY_FEEDS_REPSONSE = "de.danoeh.antennapdsp.intent.SP_APPS_QUERY_FEEDS_RESPONSE"; + public static final String ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA = "feeds"; + + @Override + public void onReceive(Context context, Intent intent) { + if (StringUtils.equals(intent.getAction(), ACTION_SP_APPS_QUERY_FEEDS_REPSONSE)) { + if (BuildConfig.DEBUG) Log.d(TAG, "Received SP_APPS_QUERY_RESPONSE"); + if (intent.hasExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA)) { + String[] feedUrls = intent.getStringArrayExtra(ACTION_SP_APPS_QUERY_FEEDS_REPSONSE_FEEDS_EXTRA); + if (feedUrls != null) { + if (BuildConfig.DEBUG) Log.d(TAG, "Received feeds list: " + Arrays.toString(feedUrls)); + for (String url : feedUrls) { + Feed f = new Feed(url, new Date()); + try { + DownloadRequester.getInstance().downloadFeed(context, f); + } catch (DownloadRequestException e) { + Log.e(TAG, "Error while trying to add feed " + url); + e.printStackTrace(); + } + } + Toast.makeText(context, R.string.sp_apps_importing_feeds_msg, Toast.LENGTH_LONG).show(); + + } else { + Log.e(TAG, "Received invalid SP_APPS_QUERY_REPSONSE: extra was null"); + } + } else { + Log.e(TAG, "Received invalid SP_APPS_QUERY_RESPONSE: Contains no extra"); + } + } + } +} diff --git a/src/de/danoeh/antennapod/service/GpodnetSyncService.java b/src/de/danoeh/antennapod/service/GpodnetSyncService.java index 71e128b55..4cb0e4cc8 100644 --- a/src/de/danoeh/antennapod/service/GpodnetSyncService.java +++ b/src/de/danoeh/antennapod/service/GpodnetSyncService.java @@ -8,7 +8,7 @@ import android.content.Intent; import android.os.IBinder; import android.support.v4.app.NotificationCompat; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.gpoddernet.GpodnetService; @@ -56,7 +56,7 @@ public class GpodnetSyncService extends Service { @Override public void onDestroy() { super.onDestroy(); - if (AppConfig.DEBUG) Log.d(TAG, "onDestroy"); + if (BuildConfig.DEBUG) Log.d(TAG, "onDestroy"); syncWaiterThread.interrupt(); } @@ -85,14 +85,14 @@ public class GpodnetSyncService extends Service { // first sync: download all subscriptions... GpodnetSubscriptionChange changes = service.getSubscriptionChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), 0); - if (AppConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + changes); + if (BuildConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + changes); processSubscriptionChanges(localSubscriptions, changes); // ... then upload all local subscriptions - if (AppConfig.DEBUG) Log.d(TAG, "Uploading subscription list: " + localSubscriptions); + if (BuildConfig.DEBUG) Log.d(TAG, "Uploading subscription list: " + localSubscriptions); GpodnetUploadChangesResponse uploadChangesResponse = service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), localSubscriptions, new LinkedList<String>()); - if (AppConfig.DEBUG) Log.d(TAG, "Uploading changes response: " + uploadChangesResponse); + if (BuildConfig.DEBUG) Log.d(TAG, "Uploading changes response: " + uploadChangesResponse); DBWriter.updateFeedDownloadURLs(GpodnetSyncService.this, uploadChangesResponse.updatedUrls).get(); GpodnetPreferences.removeAddedFeeds(localSubscriptions); GpodnetPreferences.removeRemovedFeeds(GpodnetPreferences.getRemovedFeedsCopy()); @@ -103,14 +103,14 @@ public class GpodnetSyncService extends Service { // download remote changes first... GpodnetSubscriptionChange subscriptionChanges = service.getSubscriptionChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), timestamp); - if (AppConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + subscriptionChanges); + if (BuildConfig.DEBUG) Log.d(TAG, "Downloaded subscription changes: " + subscriptionChanges); processSubscriptionChanges(localSubscriptions, subscriptionChanges); // ... then upload changes local changes - if (AppConfig.DEBUG) Log.d(TAG, String.format("Uploading subscriptions, Added: %s\nRemoved: %s", + if (BuildConfig.DEBUG) Log.d(TAG, String.format("Uploading subscriptions, Added: %s\nRemoved: %s", added.toString(), removed)); GpodnetUploadChangesResponse uploadChangesResponse = service.uploadChanges(GpodnetPreferences.getUsername(), GpodnetPreferences.getDeviceID(), added, removed); - if (AppConfig.DEBUG) Log.d(TAG, "Upload subscriptions response: " + uploadChangesResponse); + if (BuildConfig.DEBUG) Log.d(TAG, "Upload subscriptions response: " + uploadChangesResponse); GpodnetPreferences.removeAddedFeeds(added); GpodnetPreferences.removeRemovedFeeds(removed); @@ -151,7 +151,7 @@ public class GpodnetSyncService extends Service { } private void updateErrorNotification(GpodnetServiceException exception) { - if (AppConfig.DEBUG) Log.d(TAG, "Posting error notification"); + if (BuildConfig.DEBUG) Log.d(TAG, "Posting error notification"); NotificationCompat.Builder builder = new NotificationCompat.Builder(this); final String title; diff --git a/src/de/danoeh/antennapod/service/download/APRedirectHandler.java b/src/de/danoeh/antennapod/service/download/APRedirectHandler.java index 8a31c9390..ddf8d605d 100644 --- a/src/de/danoeh/antennapod/service/download/APRedirectHandler.java +++ b/src/de/danoeh/antennapod/service/download/APRedirectHandler.java @@ -1,14 +1,13 @@ package de.danoeh.antennapod.service.download; -import java.net.URI; - +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.impl.client.DefaultRedirectHandler; import org.apache.http.protocol.HttpContext; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import java.net.URI; public class APRedirectHandler extends DefaultRedirectHandler { // Identifier for logger @@ -39,12 +38,12 @@ public class APRedirectHandler extends DefaultRedirectHandler { // If anything had to be fixed, then replace the header if (!s.equals(h[0].getValue())) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Original URL: " + h[0].getValue()); response.setHeader(LOC, s); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Fixed URL: " + s); } } diff --git a/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java b/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java index 7e1c9178a..7b3f014e8 100644 --- a/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java +++ b/src/de/danoeh/antennapod/service/download/AntennapodHttpClient.java @@ -2,6 +2,7 @@ package de.danoeh.antennapod.service.download; import android.util.Log; import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import org.apache.http.client.HttpClient; import org.apache.http.client.params.HttpClientParams; import org.apache.http.conn.ClientConnectionManager; @@ -42,7 +43,7 @@ public class AntennapodHttpClient { */ public static synchronized HttpClient getHttpClient() { if (httpClient == null) { - if (AppConfig.DEBUG) Log.d(TAG, "Creating new instance of HTTP client"); + if (BuildConfig.DEBUG) Log.d(TAG, "Creating new instance of HTTP client"); HttpParams params = new BasicHttpParams(); params.setParameter(CoreProtocolPNames.USER_AGENT, AppConfig.USER_AGENT); diff --git a/src/de/danoeh/antennapod/service/download/DownloadRequest.java b/src/de/danoeh/antennapod/service/download/DownloadRequest.java index 1f4e32e1b..be22bbebb 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadRequest.java +++ b/src/de/danoeh/antennapod/service/download/DownloadRequest.java @@ -5,173 +5,214 @@ import android.os.Parcelable; public class DownloadRequest implements Parcelable { - private final String destination; - private final String source; - private final String title; - private final long feedfileId; - private final int feedfileType; - - protected int progressPercent; - protected long soFar; - protected long size; - protected int statusMsg; - - public DownloadRequest(String destination, String source, String title, - long feedfileId, int feedfileType) { - if (destination == null) { - throw new IllegalArgumentException("Destination must not be null"); - } - if (source == null) { - throw new IllegalArgumentException("Source must not be null"); - } - if (title == null) { - throw new IllegalArgumentException("Title must not be null"); - } - - this.destination = destination; - this.source = source; - this.title = title; - this.feedfileId = feedfileId; - this.feedfileType = feedfileType; - } - - private DownloadRequest(Parcel in) { - destination = in.readString(); - source = in.readString(); - title = in.readString(); - feedfileId = in.readLong(); - feedfileType = in.readInt(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(destination); - dest.writeString(source); - dest.writeString(title); - dest.writeLong(feedfileId); - dest.writeInt(feedfileType); - } - - public static final Parcelable.Creator<DownloadRequest> CREATOR = new Parcelable.Creator<DownloadRequest>() { - public DownloadRequest createFromParcel(Parcel in) { - return new DownloadRequest(in); - } - - public DownloadRequest[] newArray(int size) { - return new DownloadRequest[size]; - } - }; - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((destination == null) ? 0 : destination.hashCode()); - result = prime * result + (int) (feedfileId ^ (feedfileId >>> 32)); - result = prime * result + feedfileType; - result = prime * result + progressPercent; - result = prime * result + (int) (size ^ (size >>> 32)); - result = prime * result + (int) (soFar ^ (soFar >>> 32)); - result = prime * result + ((source == null) ? 0 : source.hashCode()); - result = prime * result + statusMsg; - result = prime * result + ((title == null) ? 0 : title.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - DownloadRequest other = (DownloadRequest) obj; - if (destination == null) { - if (other.destination != null) - return false; - } else if (!destination.equals(other.destination)) - return false; - if (feedfileId != other.feedfileId) - return false; - if (feedfileType != other.feedfileType) - return false; - if (progressPercent != other.progressPercent) - return false; - if (size != other.size) - return false; - if (soFar != other.soFar) - return false; - if (source == null) { - if (other.source != null) - return false; - } else if (!source.equals(other.source)) - return false; - if (statusMsg != other.statusMsg) - return false; - if (title == null) { - if (other.title != null) - return false; - } else if (!title.equals(other.title)) - return false; - return true; - } - - public String getDestination() { - return destination; - } - - public String getSource() { - return source; - } - - public String getTitle() { - return title; - } - - public long getFeedfileId() { - return feedfileId; - } - - public int getFeedfileType() { - return feedfileType; - } - - public int getProgressPercent() { - return progressPercent; - } - - public void setProgressPercent(int progressPercent) { - this.progressPercent = progressPercent; - } - - public long getSoFar() { - return soFar; - } - - public void setSoFar(long soFar) { - this.soFar = soFar; - } - - public long getSize() { - return size; - } - - public void setSize(long size) { - this.size = size; - } - - public int getStatusMsg() { - return statusMsg; - } - - public void setStatusMsg(int statusMsg) { - this.statusMsg = statusMsg; - } + private final String destination; + private final String source; + private final String title; + private String username; + private String password; + private final long feedfileId; + private final int feedfileType; + + protected int progressPercent; + protected long soFar; + protected long size; + protected int statusMsg; + + public DownloadRequest(String destination, String source, String title, + long feedfileId, int feedfileType, String username, String password) { + if (destination == null) { + throw new IllegalArgumentException("Destination must not be null"); + } + if (source == null) { + throw new IllegalArgumentException("Source must not be null"); + } + if (title == null) { + throw new IllegalArgumentException("Title must not be null"); + } + + this.destination = destination; + this.source = source; + this.title = title; + this.feedfileId = feedfileId; + this.feedfileType = feedfileType; + this.username = username; + this.password = password; + } + + public DownloadRequest(String destination, String source, String title, + long feedfileId, int feedfileType) { + this(destination, source, title, feedfileId, feedfileType, null, null); + } + + private DownloadRequest(Parcel in) { + destination = in.readString(); + source = in.readString(); + title = in.readString(); + feedfileId = in.readLong(); + feedfileType = in.readInt(); + if (in.dataAvail() > 0) { + username = in.readString(); + } else { + username = null; + } + if (in.dataAvail() > 0) { + password = in.readString(); + } else { + password = null; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(destination); + dest.writeString(source); + dest.writeString(title); + dest.writeLong(feedfileId); + dest.writeInt(feedfileType); + if (username != null) { + dest.writeString(username); + } + if (password != null) { + dest.writeString(password); + } + } + + public static final Parcelable.Creator<DownloadRequest> CREATOR = new Parcelable.Creator<DownloadRequest>() { + public DownloadRequest createFromParcel(Parcel in) { + return new DownloadRequest(in); + } + + public DownloadRequest[] newArray(int size) { + return new DownloadRequest[size]; + } + }; + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((destination == null) ? 0 : destination.hashCode()); + result = prime * result + (int) (feedfileId ^ (feedfileId >>> 32)); + result = prime * result + feedfileType; + result = prime * result + progressPercent; + result = prime * result + (int) (size ^ (size >>> 32)); + result = prime * result + (int) (soFar ^ (soFar >>> 32)); + result = prime * result + ((source == null) ? 0 : source.hashCode()); + result = prime * result + statusMsg; + result = prime * result + ((title == null) ? 0 : title.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + DownloadRequest other = (DownloadRequest) obj; + if (destination == null) { + if (other.destination != null) + return false; + } else if (!destination.equals(other.destination)) + return false; + if (feedfileId != other.feedfileId) + return false; + if (feedfileType != other.feedfileType) + return false; + if (progressPercent != other.progressPercent) + return false; + if (size != other.size) + return false; + if (soFar != other.soFar) + return false; + if (source == null) { + if (other.source != null) + return false; + } else if (!source.equals(other.source)) + return false; + if (statusMsg != other.statusMsg) + return false; + if (title == null) { + if (other.title != null) + return false; + } else if (!title.equals(other.title)) + return false; + return true; + } + + public String getDestination() { + return destination; + } + + public String getSource() { + return source; + } + + public String getTitle() { + return title; + } + + public long getFeedfileId() { + return feedfileId; + } + + public int getFeedfileType() { + return feedfileType; + } + + public int getProgressPercent() { + return progressPercent; + } + + public void setProgressPercent(int progressPercent) { + this.progressPercent = progressPercent; + } + + public long getSoFar() { + return soFar; + } + + public void setSoFar(long soFar) { + this.soFar = soFar; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public int getStatusMsg() { + return statusMsg; + } + + public void setStatusMsg(int statusMsg) { + this.statusMsg = statusMsg; + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public void setUsername(String username) { + this.username = username; + } + + public void setPassword(String password) { + this.password = password; + } } diff --git a/src/de/danoeh/antennapod/service/download/DownloadService.java b/src/de/danoeh/antennapod/service/download/DownloadService.java index c27b4d4fe..72e0852bb 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadService.java +++ b/src/de/danoeh/antennapod/service/download/DownloadService.java @@ -1,20 +1,5 @@ package de.danoeh.antennapod.service.download; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.xml.parsers.ParserConfigurationException; - -import android.media.MediaMetadataRetriever; -import de.danoeh.antennapod.storage.*; -import org.xml.sax.SAXException; - import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationManager; @@ -26,27 +11,37 @@ import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; import android.graphics.BitmapFactory; -import android.os.AsyncTask; +import android.media.MediaMetadataRetriever; import android.os.Binder; import android.os.Handler; import android.os.IBinder; import android.support.v4.app.NotificationCompat; import android.util.Log; import android.webkit.URLUtil; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.DownloadActivity; +import de.danoeh.antennapod.activity.DownloadAuthenticationActivity; import de.danoeh.antennapod.activity.DownloadLogActivity; -import de.danoeh.antennapod.feed.EventDistributor; -import de.danoeh.antennapod.feed.Feed; -import de.danoeh.antennapod.feed.FeedImage; -import de.danoeh.antennapod.feed.FeedItem; -import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.feed.*; +import de.danoeh.antennapod.storage.*; import de.danoeh.antennapod.syndication.handler.FeedHandler; import de.danoeh.antennapod.syndication.handler.UnsupportedFeedtypeException; import de.danoeh.antennapod.util.ChapterUtils; import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.InvalidFeedException; +import org.apache.commons.lang3.StringUtils; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; /** * Manages the download of feedfiles in the app. Downloads can be enqueued viathe startService intent. @@ -140,11 +135,11 @@ public class DownloadService extends Service { @Override public void run() { - if (AppConfig.DEBUG) Log.d(TAG, "downloadCompletionThread was started"); + if (BuildConfig.DEBUG) Log.d(TAG, "downloadCompletionThread was started"); while (!isInterrupted()) { try { Downloader downloader = downloadExecutor.take().get(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received 'Download Complete' - message."); removeDownload(downloader); DownloadStatus status = downloader.getResult(); @@ -162,21 +157,25 @@ public class DownloadService extends Service { } } else { numberOfDownloads.decrementAndGet(); - if (!successful && !status.isCancelled()) { - Log.e(TAG, "Download failed"); - saveDownloadStatus(status); + if (!status.isCancelled()) { + if (status.getReason() == DownloadError.ERROR_UNAUTHORIZED) { + postAuthenticationNotification(downloader.getDownloadRequest()); + } else { + Log.e(TAG, "Download failed"); + saveDownloadStatus(status); + } } sendDownloadHandledIntent(); queryDownloadsAsync(); } } catch (InterruptedException e) { - if (AppConfig.DEBUG) Log.d(TAG, "DownloadCompletionThread was interrupted"); + if (BuildConfig.DEBUG) Log.d(TAG, "DownloadCompletionThread was interrupted"); } catch (ExecutionException e) { e.printStackTrace(); numberOfDownloads.decrementAndGet(); } } - if (AppConfig.DEBUG) Log.d(TAG, "End of downloadCompletionThread"); + if (BuildConfig.DEBUG) Log.d(TAG, "End of downloadCompletionThread"); } }; @@ -193,7 +192,7 @@ public class DownloadService extends Service { @SuppressLint("NewApi") @Override public void onCreate() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Service started"); isRunning = true; handler = new Handler(); @@ -224,7 +223,9 @@ public class DownloadService extends Service { t.setPriority(Thread.MIN_PRIORITY); return t; } - })); + } + ) + ); schedExecutor = new ScheduledThreadPoolExecutor(SCHED_EX_POOL_SIZE, new ThreadFactory() { @@ -255,7 +256,7 @@ public class DownloadService extends Service { @Override public void onDestroy() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Service shutting down"); isRunning = false; updateReport(); @@ -274,8 +275,9 @@ public class DownloadService extends Service { @SuppressLint("NewApi") private void setupNotificationBuilders() { PendingIntent pIntent = PendingIntent.getActivity(this, 0, new Intent( - this, DownloadActivity.class), - PendingIntent.FLAG_UPDATE_CURRENT); + this, DownloadActivity.class), + PendingIntent.FLAG_UPDATE_CURRENT + ); Bitmap icon = BitmapFactory.decodeResource(getResources(), R.drawable.stat_notify_sync); @@ -284,14 +286,15 @@ public class DownloadService extends Service { notificationBuilder = new Notification.BigTextStyle( new Notification.Builder(this).setOngoing(true) .setContentIntent(pIntent).setLargeIcon(icon) - .setSmallIcon(R.drawable.stat_notify_sync)); + .setSmallIcon(R.drawable.stat_notify_sync) + ); } else { notificationCompatBuilder = new NotificationCompat.Builder(this) .setOngoing(true).setContentIntent(pIntent) .setLargeIcon(icon) .setSmallIcon(R.drawable.stat_notify_sync); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Notification set up"); } @@ -368,7 +371,7 @@ public class DownloadService extends Service { throw new IllegalArgumentException( "ACTION_CANCEL_DOWNLOAD intent needs download url extra"); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Cancelling download with url " + url); Downloader d = getDownloader(url); if (d != null) { @@ -380,7 +383,7 @@ public class DownloadService extends Service { } else if (intent.getAction().equals(ACTION_CANCEL_ALL_DOWNLOADS)) { for (Downloader d : downloads) { d.cancel(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Cancelled all downloads"); } sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED)); @@ -392,7 +395,7 @@ public class DownloadService extends Service { }; private void onDownloadQueued(Intent intent) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received enqueue request"); DownloadRequest request = intent.getParcelableExtra(EXTRA_REQUEST); if (request == null) { @@ -413,12 +416,13 @@ public class DownloadService extends Service { private Downloader getDownloader(DownloadRequest request) { if (URLUtil.isHttpUrl(request.getSource()) - || URLUtil.isHttpsUrl(request.getSource())) { + || URLUtil.isHttpsUrl(request.getSource())) { return new HttpDownloader(request); } Log.e(TAG, "Could not find appropriate downloader for " - + request.getSource()); + + request.getSource() + ); return null; } @@ -430,11 +434,11 @@ public class DownloadService extends Service { handler.post(new Runnable() { @Override public void run() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Removing downloader: " + d.getDownloadRequest().getSource()); boolean rc = downloads.remove(d); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Result of downloads.remove: " + rc); DownloadRequester.getInstance().removeDownload(d.getDownloadRequest()); sendBroadcast(new Intent(ACTION_DOWNLOADS_CONTENT_CHANGED)); @@ -484,7 +488,7 @@ public class DownloadService extends Service { } if (createReport) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating report"); // create notification object Notification notification = new NotificationCompat.Builder(this) @@ -495,19 +499,22 @@ public class DownloadService extends Service { .setContentText( String.format( getString(R.string.download_report_content), - successfulDownloads, failedDownloads)) + successfulDownloads, failedDownloads) + ) .setSmallIcon(R.drawable.stat_notify_sync) .setLargeIcon( BitmapFactory.decodeResource(getResources(), - R.drawable.stat_notify_sync)) + R.drawable.stat_notify_sync) + ) .setContentIntent( PendingIntent.getActivity(this, 0, new Intent(this, - DownloadLogActivity.class), 0)) + DownloadLogActivity.class), 0) + ) .setAutoCancel(true).getNotification(); NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); nm.notify(REPORT_ID, notification); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "No report is created"); } completedDownloads.clear(); @@ -530,12 +537,12 @@ public class DownloadService extends Service { * Check if there's something else to download, otherwise stop */ void queryDownloads() { - if (AppConfig.DEBUG) { + if (BuildConfig.DEBUG) { Log.d(TAG, numberOfDownloads.get() + " downloads left"); } if (numberOfDownloads.get() <= 0 && DownloadRequester.getInstance().hasNoDownloads()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Number of downloads is " + numberOfDownloads.get() + ", attempting shutdown"); stopSelf(); } else { @@ -544,11 +551,40 @@ public class DownloadService extends Service { } } + private void postAuthenticationNotification(final DownloadRequest downloadRequest) { + handler.post(new Runnable() { + @Override + public void run() { + final String resourceTitle = (downloadRequest.getTitle() != null) + ? downloadRequest.getTitle() : downloadRequest.getSource(); + + final Intent activityIntent = new Intent(getApplicationContext(), DownloadAuthenticationActivity.class); + activityIntent.putExtra(DownloadAuthenticationActivity.ARG_DOWNLOAD_REQUEST, downloadRequest); + activityIntent.putExtra(DownloadAuthenticationActivity.ARG_SEND_TO_DOWNLOAD_REQUESTER_BOOL, true); + final PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, activityIntent, PendingIntent.FLAG_ONE_SHOT); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(DownloadService.this); + builder.setTicker(getText(R.string.authentication_notification_title)) + .setContentTitle(getText(R.string.authentication_notification_title)) + .setContentText(getText(R.string.authentication_notification_msg)) + .setStyle(new NotificationCompat.BigTextStyle().bigText(getText(R.string.authentication_notification_msg) + + ": " + resourceTitle)) + .setSmallIcon(R.drawable.ic_stat_authentication) + .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_stat_authentication)) + .setAutoCancel(true) + .setContentIntent(contentIntent); + Notification n = builder.build(); + NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(downloadRequest.getSource().hashCode(), n); + } + }); + } + /** * Is called whenever a Feed is downloaded */ private void handleCompletedFeedDownload(DownloadRequest request) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Handling completed Feed Download"); syncExecutor.execute(new FeedSyncThread(request)); @@ -558,7 +594,7 @@ public class DownloadService extends Service { * Is called whenever a Feed-Image is downloaded */ private void handleCompletedImageDownload(DownloadStatus status, DownloadRequest request) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Handling completed Image Download"); syncExecutor.execute(new ImageHandlerThread(status, request)); } @@ -567,7 +603,7 @@ public class DownloadService extends Service { * Is called whenever a FeedMedia is downloaded. */ private void handleCompletedFeedMediaDownload(DownloadStatus status, DownloadRequest request) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Handling completed FeedMedia Download"); syncExecutor.execute(new MediaHandlerThread(status, request)); } @@ -598,6 +634,7 @@ public class DownloadService extends Service { Feed feed = new Feed(request.getSource(), new Date()); feed.setFile_url(request.getDestination()); feed.setDownloaded(true); + feed.setPreferences(new FeedPreferences(0, true, request.getUsername(), request.getPassword())); reason = null; String reasonDetailed = null; @@ -606,19 +643,22 @@ public class DownloadService extends Service { try { feed = feedHandler.parseFeed(feed); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, feed.getTitle() + " parsed"); if (checkFeedData(feed) == false) { throw new InvalidFeedException(); } + + removeDuplicateImages(feed); // duplicate images have to removed because the DownloadRequester does not accept two downloads with the same download URL yet. + // Save information of feed in DB savedFeed = DBTasks.updateFeed(DownloadService.this, feed); // Download Feed Image if provided and not downloaded if (savedFeed.getImage() != null && savedFeed.getImage().isDownloaded() == false) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Feed has image; Downloading...."); - savedFeed.getImage().setFeed(savedFeed); + savedFeed.getImage().setOwner(savedFeed); final Feed savedFeedRef = savedFeed; try { requester.downloadImage(DownloadService.this, @@ -633,9 +673,36 @@ public class DownloadService extends Service { .getImage() .getHumanReadableIdentifier(), DownloadError.ERROR_REQUEST_ERROR, - false, e.getMessage())); + false, e.getMessage() + ) + ); } } + // download FeedItem images if provided and not downloaded + for (FeedItem item : savedFeed.getItems()) { + if (item.hasItemImage() && (!item.getImage().isDownloaded())) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Item has image; Downloading...."); + try { + requester.downloadImage(DownloadService.this, + item.getImage()); + } catch (DownloadRequestException e) { + e.printStackTrace(); + DBWriter.addDownloadStatus( + DownloadService.this, + new DownloadStatus( + item.getImage(), + item + .getImage() + .getHumanReadableIdentifier(), + DownloadError.ERROR_REQUEST_ERROR, + false, e.getMessage() + ) + ); + } + } + } + } catch (SAXException e) { successful = false; @@ -689,10 +756,29 @@ public class DownloadService extends Service { Log.e(TAG, "Feed has invalid items"); return false; } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Feed appears to be valid."); return true; + } + /** + * Checks if the FeedItems of this feed have images that point + * to the same URL. If two FeedItems have an image that points to + * the same URL, the reference of the second item is removed, so that every image + * reference is unique. + */ + private void removeDuplicateImages(Feed feed) { + for (int x = 0; x < feed.getItems().size(); x++) { + for (int y = x + 1; y < feed.getItems().size(); y++) { + FeedItem item1 = feed.getItems().get(x); + FeedItem item2 = feed.getItems().get(y); + if (item1.hasItemImage() && item2.hasItemImage()) { + if (StringUtils.equals(item1.getImage().getDownload_url(), item2.getImage().getDownload_url())) { + item2.setImage(null); + } + } + } + } } private boolean hasValidFeedItems(Feed feed) { @@ -719,12 +805,12 @@ public class DownloadService extends Service { private void cleanup(Feed feed) { if (feed.getFile_url() != null) { if (new File(feed.getFile_url()).delete()) - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Successfully deleted cache file."); else Log.e(TAG, "Failed to delete cache file."); feed.setFile_url(null); - } else if (AppConfig.DEBUG) { + } else if (BuildConfig.DEBUG) { Log.d(TAG, "Didn't delete cache file: File url is not set."); } } @@ -807,7 +893,7 @@ public class DownloadService extends Service { mmr.setDataSource(media.getFile_url()); String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); media.setDuration(Integer.parseInt(durationStr)); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Duration of file is " + media.getDuration()); } catch (NumberFormatException e) { e.printStackTrace(); @@ -854,7 +940,7 @@ public class DownloadService extends Service { * Schedules the notification updater task if it hasn't been scheduled yet. */ private void setupNotificationUpdater() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Setting up notification updater"); if (notificationUpdater == null) { notificationUpdater = new NotificationUpdater(); diff --git a/src/de/danoeh/antennapod/service/download/DownloadStatus.java b/src/de/danoeh/antennapod/service/download/DownloadStatus.java index 487c3b3de..b240cddbc 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadStatus.java +++ b/src/de/danoeh/antennapod/service/download/DownloadStatus.java @@ -1,10 +1,10 @@ package de.danoeh.antennapod.service.download; -import java.util.Date; - import de.danoeh.antennapod.feed.FeedFile; import de.danoeh.antennapod.util.DownloadError; +import java.util.Date; + /** Contains status attributes for one download */ public class DownloadStatus { /** diff --git a/src/de/danoeh/antennapod/service/download/HttpDownloader.java b/src/de/danoeh/antennapod/service/download/HttpDownloader.java index fc2b3178b..84bafb027 100644 --- a/src/de/danoeh/antennapod/service/download/HttpDownloader.java +++ b/src/de/danoeh/antennapod/service/download/HttpDownloader.java @@ -2,20 +2,27 @@ package de.danoeh.antennapod.service.download; import android.net.http.AndroidHttpClient; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.feed.FeedImage; import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.StorageUtils; +import de.danoeh.antennapod.util.URIUtil; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.auth.BasicScheme; import java.io.*; -import java.net.*; +import java.net.HttpURLConnection; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; public class HttpDownloader extends Downloader { private static final String TAG = "HttpDownloader"; @@ -26,24 +33,37 @@ public class HttpDownloader extends Downloader { super(request); } - private URI getURIFromRequestUrl(String source) { - try { - URL url = new URL(source); - return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(e); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - } - @Override protected void download() { + File destination = new File(request.getDestination()); + if (destination.exists()) { + Log.w(TAG, "File already exists"); + if (request.getFeedfileType() != FeedImage.FEEDFILETYPE_FEEDIMAGE) { + onFail(DownloadError.ERROR_FILE_EXISTS, null); + return; + } else { + onSuccess(); + return; + } + } + HttpClient httpClient = AntennapodHttpClient.getHttpClient(); BufferedOutputStream out = null; InputStream connection = null; try { - HttpGet httpGet = new HttpGet(getURIFromRequestUrl(request.getSource())); + HttpGet httpGet = new HttpGet(URIUtil.getURIFromRequestUrl(request.getSource())); + String userInfo = httpGet.getURI().getUserInfo(); + if (userInfo != null) { + String[] parts = userInfo.split(":"); + if (parts.length == 2) { + httpGet.addHeader(BasicScheme.authenticate( + new UsernamePasswordCredentials(parts[0], parts[1]), + "UTF-8", false)); + } + } else if (!StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) { + httpGet.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials(request.getUsername(), + request.getPassword()), "UTF-8", false)); + } HttpResponse response = httpClient.execute(httpGet); HttpEntity httpEntity = response.getEntity(); int responseCode = response.getStatusLine().getStatusCode(); @@ -52,12 +72,20 @@ public class HttpDownloader extends Downloader { final boolean isGzip = contentEncodingHeader != null && contentEncodingHeader.getValue().equalsIgnoreCase("gzip"); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Response code is " + responseCode); if (responseCode != HttpURLConnection.HTTP_OK || httpEntity == null) { - onFail(DownloadError.ERROR_HTTP_DATA_ERROR, - String.valueOf(responseCode)); + final DownloadError error; + final String details; + if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { + error = DownloadError.ERROR_UNAUTHORIZED; + details = String.valueOf(responseCode); + } else { + error = DownloadError.ERROR_HTTP_DATA_ERROR; + details = String.valueOf(responseCode); + } + onFail(error, details); return; } @@ -66,13 +94,6 @@ public class HttpDownloader extends Downloader { return; } - File destination = new File(request.getDestination()); - if (destination.exists()) { - Log.w(TAG, "File already exists"); - onFail(DownloadError.ERROR_FILE_EXISTS, null); - return; - } - connection = new BufferedInputStream(AndroidHttpClient .getUngzippedContent(httpEntity)); out = new BufferedOutputStream(new FileOutputStream( @@ -80,17 +101,17 @@ public class HttpDownloader extends Downloader { byte[] buffer = new byte[BUFFER_SIZE]; int count = 0; request.setStatusMsg(R.string.download_running); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Getting size of download"); request.setSize(httpEntity.getContentLength()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Size is " + request.getSize()); if (request.getSize() < 0) { request.setSize(DownloadStatus.SIZE_UNKNOWN); } long freeSpace = StorageUtils.getFreeSpaceAvailable(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Free space is " + freeSpace); if (request.getSize() != DownloadStatus.SIZE_UNKNOWN @@ -99,7 +120,7 @@ public class HttpDownloader extends Downloader { return; } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting download"); while (!cancelled && (count = connection.read(buffer)) != -1) { @@ -121,7 +142,8 @@ public class HttpDownloader extends Downloader { "Download completed but size: " + request.getSoFar() + " does not equal expected size " + - request.getSize()); + request.getSize() + ); return; } onSuccess(); @@ -150,13 +172,13 @@ public class HttpDownloader extends Downloader { } private void onSuccess() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Download was successful"); result.setSuccessful(); } private void onFail(DownloadError reason, String reasonDetailed) { - if (AppConfig.DEBUG) { + if (BuildConfig.DEBUG) { Log.d(TAG, "Download failed"); } result.setFailed(reason, reasonDetailed); @@ -164,7 +186,7 @@ public class HttpDownloader extends Downloader { } private void onCancelled() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Download was cancelled"); result.setCancelled(); cleanup(); @@ -178,11 +200,11 @@ public class HttpDownloader extends Downloader { File dest = new File(request.getDestination()); if (dest.exists()) { boolean rc = dest.delete(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Deleted file " + dest.getName() + "; Result: " + rc); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "cleanup() didn't delete file: does not exist."); } } diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackService.java b/src/de/danoeh/antennapod/service/playback/PlaybackService.java index 6bc8c4127..fb2569bfd 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackService.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackService.java @@ -22,7 +22,7 @@ import android.util.Log; import android.util.Pair; import android.view.KeyEvent; import android.view.SurfaceHolder; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.AudioplayerActivity; @@ -153,7 +153,7 @@ public class PlaybackService extends Service { @Override public boolean onUnbind(Intent intent) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received onUnbind event"); return super.onUnbind(intent); } @@ -196,7 +196,7 @@ public class PlaybackService extends Service { @Override public void onCreate() { super.onCreate(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Service created."); isRunning = true; @@ -218,7 +218,7 @@ public class PlaybackService extends Service { @Override public void onDestroy() { super.onDestroy(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Service is about to be destroyed"); isRunning = false; started = false; @@ -234,7 +234,7 @@ public class PlaybackService extends Service { @Override public IBinder onBind(Intent intent) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received onBind event"); return mBinder; } @@ -243,7 +243,7 @@ public class PlaybackService extends Service { public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "OnStartCommand called"); final int keycode = intent.getIntExtra(MediaButtonReceiver.EXTRA_KEYCODE, -1); final Playable playable = intent.getParcelableExtra(EXTRA_PLAYABLE); @@ -253,12 +253,12 @@ public class PlaybackService extends Service { } if ((flags & Service.START_FLAG_REDELIVERY) != 0) { - if (AppConfig.DEBUG) Log.d(TAG, "onStartCommand is a redelivered intent, calling stopForeground now."); + if (BuildConfig.DEBUG) Log.d(TAG, "onStartCommand is a redelivered intent, calling stopForeground now."); stopForeground(true); } else { if (keycode != -1) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received media button event"); handleKeycode(keycode); } else { @@ -279,7 +279,7 @@ public class PlaybackService extends Service { * Handles media button events */ private void handleKeycode(int keycode) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Handling keycode: " + keycode); final PlayerStatus status = mediaPlayer.getPSMPInfo().playerStatus; @@ -326,7 +326,7 @@ public class PlaybackService extends Service { * mediaplayer. */ public void setVideoSurface(SurfaceHolder sh) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Setting display"); mediaPlayer.setVideoSurface(sh); } @@ -394,15 +394,18 @@ public class PlaybackService extends Service { break; case PLAYING: - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Audiofocus successfully requested"); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Resuming/Starting playback"); taskManager.startPositionSaver(); taskManager.startWidgetUpdater(); setupNotification(newInfo); break; + case ERROR: + writePlaybackPreferencesNoMediaPlaying(); + break; } @@ -451,7 +454,7 @@ public class PlaybackService extends Service { mediaPlayer.pause(true, false); } sendNotificationBroadcast(NOTIFICATION_TYPE_ERROR, what); - setCurrentlyPlayingMedia(PlaybackPreferences.NO_MEDIA_PLAYING); + writePlaybackPreferencesNoMediaPlaying(); stopSelf(); return true; } @@ -469,7 +472,7 @@ public class PlaybackService extends Service { }; private void endPlayback(boolean playNextEpisode) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Playback ended"); final Playable media = mediaPlayer.getPSMPInfo().playable; @@ -509,7 +512,7 @@ public class PlaybackService extends Service { playNextEpisode = playNextEpisode && loadNextItem && UserPreferences.isFollowQueue(); if (loadNextItem) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading next item in queue"); nextMedia = nextItem.getMedia(); } @@ -518,11 +521,11 @@ public class PlaybackService extends Service { final boolean stream; if (playNextEpisode) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Playback of next episode will start immediately."); prepareImmediately = startWhenPrepared = true; } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "No more episodes available to play"); prepareImmediately = startWhenPrepared = false; @@ -530,7 +533,7 @@ public class PlaybackService extends Service { stopWidgetUpdater(); } - writePlaybackPreferences(); + writePlaybackPreferencesNoMediaPlaying(); if (nextMedia != null) { stream = !media.localFileAvailable(); mediaPlayer.playMediaObject(nextMedia, stream, startWhenPrepared, prepareImmediately); @@ -543,7 +546,7 @@ public class PlaybackService extends Service { } public void setSleepTimer(long waitingTime) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime) + " milliseconds"); taskManager.setSleepTimer(waitingTime); @@ -555,9 +558,22 @@ public class PlaybackService extends Service { sendNotificationBroadcast(NOTIFICATION_TYPE_SLEEPTIMER_UPDATE, 0); } + private void writePlaybackPreferencesNoMediaPlaying() { + SharedPreferences.Editor editor = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()).edit(); + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEED_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.putLong( + PlaybackPreferences.PREF_CURRENTLY_PLAYING_FEEDMEDIA_ID, + PlaybackPreferences.NO_MEDIA_PLAYING); + editor.commit(); + } + private void writePlaybackPreferences() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Writing playback preferences"); SharedPreferences.Editor editor = PreferenceManager @@ -641,7 +657,7 @@ public class PlaybackService extends Service { @Override protected Void doInBackground(Void... params) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting background work"); if (android.os.Build.VERSION.SDK_INT >= 11) { if (info.playable != null) { @@ -701,7 +717,7 @@ public class PlaybackService extends Service { notification = notificationBuilder.getNotification(); } startForeground(NOTIFICATION_ID, notification); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Notification set up"); } } @@ -728,7 +744,7 @@ public class PlaybackService extends Service { float playbackSpeed = getCurrentPlaybackSpeed(); final Playable playable = mediaPlayer.getPSMPInfo().playable; if (position != INVALID_TIME && duration != INVALID_TIME && playable != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Saving current position to " + position); if (updatePlayedDuration && playable instanceof FeedMedia) { FeedMedia m = (FeedMedia) playable; @@ -738,7 +754,7 @@ public class PlaybackService extends Service { if (FlattrUtils.hasToken() && UserPreferences.isAutoFlattr() && item.getPaymentLink() != null && item.getFlattrStatus().getUnflattred() && (m.getPlayedDuration() > UserPreferences.getPlayedDurationAutoflattrThreshold() * duration)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "saveCurrentPosition: performing auto flattr since played duration " + Integer.toString(m.getPlayedDuration()) + " is " + UserPreferences.getPlayedDurationAutoflattrThreshold() * 100 + "% of file duration " + Integer.toString(duration)); item.getFlattrStatus().setFlattrQueue(); @@ -832,7 +848,7 @@ public class PlaybackService extends Service { editor.apply(); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "RemoteControlClient state was refreshed"); } } @@ -876,10 +892,10 @@ public class PlaybackService extends Service { intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) { int state = intent.getIntExtra("state", -1); if (state != -1) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Headset plug event. State is " + state); if (state == UNPLUGGED) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Headset was unplugged during playback."); pauseIfPauseOnDisconnect(); } @@ -895,7 +911,7 @@ public class PlaybackService extends Service { @Override public void onReceive(Context context, Intent intent) { // sound is about to change, eg. bluetooth -> speaker - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Pausing playback because audio is becoming noisy"); pauseIfPauseOnDisconnect(); } @@ -928,7 +944,7 @@ public class PlaybackService extends Service { public void onReceive(Context context, Intent intent) { if (intent.getAction() != null && intent.getAction().equals(ACTION_SKIP_CURRENT_EPISODE)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received SKIP_CURRENT_EPISODE intent"); mediaPlayer.endPlayback(); } @@ -1028,10 +1044,4 @@ public class PlaybackService extends Service { return mediaPlayer.getVideoSize(); } - private void setCurrentlyPlayingMedia(long id) { - SharedPreferences.Editor editor = PreferenceManager - .getDefaultSharedPreferences(getApplicationContext()).edit(); - editor.putLong(PlaybackPreferences.PREF_CURRENTLY_PLAYING_MEDIA, id); - editor.commit(); - } } diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java b/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java index 30f6de458..82759a902 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackServiceMediaPlayer.java @@ -7,7 +7,7 @@ import android.media.RemoteControlClient; import android.util.Log; import android.util.Pair; import android.view.SurfaceHolder; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.MediaType; import de.danoeh.antennapod.preferences.UserPreferences; @@ -75,7 +75,7 @@ public class PlaybackServiceMediaPlayer { new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { - if (AppConfig.DEBUG) Log.d(TAG, "Rejected execution of runnable"); + if (BuildConfig.DEBUG) Log.d(TAG, "Rejected execution of runnable"); } }); @@ -116,7 +116,7 @@ public class PlaybackServiceMediaPlayer { public void playMediaObject(final Playable playable, final boolean stream, final boolean startWhenPrepared, final boolean prepareImmediately) { if (playable == null) throw new IllegalArgumentException("playable = null"); - if (AppConfig.DEBUG) Log.d(TAG, "Play media object."); + if (BuildConfig.DEBUG) Log.d(TAG, "Play media object."); executor.submit(new Runnable() { @Override public void run() { @@ -245,10 +245,10 @@ public class PlaybackServiceMediaPlayer { media.onPlaybackStart(); } else { - if (AppConfig.DEBUG) Log.e(TAG, "Failed to request audio focus"); + if (BuildConfig.DEBUG) Log.e(TAG, "Failed to request audio focus"); } } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Call to resume() was ignored because current state of PSMP object is " + playerStatus); } } @@ -271,7 +271,7 @@ public class PlaybackServiceMediaPlayer { playerLock.lock(); if (playerStatus == PlayerStatus.PLAYING) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Pausing playback."); mediaPlayer.pause(); setPlayerStatus(PlayerStatus.PAUSED, media); @@ -284,7 +284,7 @@ public class PlaybackServiceMediaPlayer { reinit(); } } else { - if (AppConfig.DEBUG) Log.d(TAG, "Ignoring call to pause: Player is in " + playerStatus + " state"); + if (BuildConfig.DEBUG) Log.d(TAG, "Ignoring call to pause: Player is in " + playerStatus + " state"); } playerLock.unlock(); @@ -305,7 +305,7 @@ public class PlaybackServiceMediaPlayer { playerLock.lock(); if (playerStatus == PlayerStatus.INITIALIZED) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Preparing media player"); setPlayerStatus(PlayerStatus.PREPARING, media); try { @@ -333,7 +333,7 @@ public class PlaybackServiceMediaPlayer { throw new IllegalStateException("Player is not in PREPARING state"); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Resource prepared"); if (mediaType == MediaType.VIDEO) { @@ -346,7 +346,7 @@ public class PlaybackServiceMediaPlayer { } if (media.getDuration() == 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Setting duration of media"); media.setDuration(mediaPlayer.getDuration()); } @@ -375,7 +375,7 @@ public class PlaybackServiceMediaPlayer { } else if (mediaPlayer != null) { mediaPlayer.reset(); } else { - if (AppConfig.DEBUG) Log.d(TAG, "Call to reinit was ignored: media and mediaPlayer were null"); + if (BuildConfig.DEBUG) Log.d(TAG, "Call to reinit was ignored: media and mediaPlayer were null"); } playerLock.unlock(); } @@ -385,14 +385,13 @@ public class PlaybackServiceMediaPlayer { /** * Seeks to the specified position. If the PSMP object is in an invalid state, this method will do nothing. - * Invalid time values (< 0) will be ignored. + * @param t The position to seek to in milliseconds. t < 0 will be interpreted as t = 0 * <p/> * This method is executed on the caller's thread. */ private void seekToSync(int t) { if (t < 0) { - if (AppConfig.DEBUG) Log.d(TAG, "Received invalid value for t"); - return; + t = 0; } playerLock.lock(); @@ -535,7 +534,7 @@ public class PlaybackServiceMediaPlayer { if (media != null && media.getMediaType() == MediaType.AUDIO) { if (mediaPlayer.canSetSpeed()) { mediaPlayer.setPlaybackSpeed((float) speed); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Playback speed was set to " + speed); callback.playbackSpeedChanged(speed); } @@ -611,7 +610,7 @@ public class PlaybackServiceMediaPlayer { @Override public void run() { playerLock.lock(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Resetting video surface"); mediaPlayer.setDisplay(null); reinit(); @@ -666,7 +665,7 @@ public class PlaybackServiceMediaPlayer { private synchronized void setPlayerStatus(PlayerStatus newStatus, Playable newMedia) { if (newStatus == null) throw new IllegalArgumentException("newStatus = null"); - if (AppConfig.DEBUG) Log.d(TAG, "Setting player status to " + newStatus); + if (BuildConfig.DEBUG) Log.d(TAG, "Setting player status to " + newStatus); this.playerStatus = newStatus; this.media = newMedia; @@ -697,13 +696,13 @@ public class PlaybackServiceMediaPlayer { switch (focusChange) { case AudioManager.AUDIOFOCUS_LOSS: - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Lost audio focus"); pause(true, false); callback.shouldStop(); break; case AudioManager.AUDIOFOCUS_GAIN: - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Gained audio focus"); if (pausedBecauseOfTransientAudiofocusLoss) // we paused => play now resume(); @@ -714,13 +713,13 @@ public class PlaybackServiceMediaPlayer { case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: if (playerStatus == PlayerStatus.PLAYING) { if (!UserPreferences.shouldPauseForFocusLoss()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Lost audio focus temporarily. Ducking..."); audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, 0); pausedBecauseOfTransientAudiofocusLoss = false; } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Lost audio focus temporarily. Could duck, but won't, pausing..."); pause(false, false); pausedBecauseOfTransientAudiofocusLoss = true; @@ -729,7 +728,7 @@ public class PlaybackServiceMediaPlayer { break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: if (playerStatus == PlayerStatus.PLAYING) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Lost audio focus temporarily. Pausing..."); pause(false, false); pausedBecauseOfTransientAudiofocusLoss = true; @@ -756,6 +755,7 @@ public class PlaybackServiceMediaPlayer { mediaPlayer.reset(); } + audioManager.abandonAudioFocus(audioFocusChangeListener); callback.endPlayback(true); playerLock.unlock(); diff --git a/src/de/danoeh/antennapod/service/playback/PlaybackServiceTaskManager.java b/src/de/danoeh/antennapod/service/playback/PlaybackServiceTaskManager.java index 0c1878e18..3ab06910a 100644 --- a/src/de/danoeh/antennapod/service/playback/PlaybackServiceTaskManager.java +++ b/src/de/danoeh/antennapod/service/playback/PlaybackServiceTaskManager.java @@ -2,7 +2,7 @@ package de.danoeh.antennapod.service.playback; import android.content.Context; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.EventDistributor; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.storage.DBReader; @@ -144,9 +144,9 @@ public class PlaybackServiceTaskManager { positionSaverFuture = schedExecutor.scheduleWithFixedDelay(positionSaver, POSITION_SAVER_WAITING_INTERVAL, POSITION_SAVER_WAITING_INTERVAL, TimeUnit.MILLISECONDS); - if (AppConfig.DEBUG) Log.d(TAG, "Started PositionSaver"); + if (BuildConfig.DEBUG) Log.d(TAG, "Started PositionSaver"); } else { - if (AppConfig.DEBUG) Log.d(TAG, "Call to startPositionSaver was ignored."); + if (BuildConfig.DEBUG) Log.d(TAG, "Call to startPositionSaver was ignored."); } } @@ -163,7 +163,7 @@ public class PlaybackServiceTaskManager { public synchronized void cancelPositionSaver() { if (isPositionSaverActive()) { positionSaverFuture.cancel(false); - if (AppConfig.DEBUG) Log.d(TAG, "Cancelled PositionSaver"); + if (BuildConfig.DEBUG) Log.d(TAG, "Cancelled PositionSaver"); } } @@ -181,9 +181,9 @@ public class PlaybackServiceTaskManager { widgetUpdaterFuture = schedExecutor.scheduleWithFixedDelay(widgetUpdater, WIDGET_UPDATER_NOTIFICATION_INTERVAL, WIDGET_UPDATER_NOTIFICATION_INTERVAL, TimeUnit.MILLISECONDS); - if (AppConfig.DEBUG) Log.d(TAG, "Started WidgetUpdater"); + if (BuildConfig.DEBUG) Log.d(TAG, "Started WidgetUpdater"); } else { - if (AppConfig.DEBUG) Log.d(TAG, "Call to startWidgetUpdater was ignored."); + if (BuildConfig.DEBUG) Log.d(TAG, "Call to startWidgetUpdater was ignored."); } } @@ -198,7 +198,7 @@ public class PlaybackServiceTaskManager { if (waitingTime <= 0) throw new IllegalArgumentException("waitingTime <= 0"); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Setting sleep timer to " + Long.toString(waitingTime) + " milliseconds"); if (isSleepTimerActive()) { @@ -220,7 +220,7 @@ public class PlaybackServiceTaskManager { */ public synchronized void disableSleepTimer() { if (isSleepTimerActive()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Disabling sleep timer"); sleepTimerFuture.cancel(true); } @@ -251,7 +251,7 @@ public class PlaybackServiceTaskManager { public synchronized void cancelWidgetUpdater() { if (isWidgetUpdaterActive()) { widgetUpdaterFuture.cancel(false); - if (AppConfig.DEBUG) Log.d(TAG, "Cancelled WidgetUpdater"); + if (BuildConfig.DEBUG) Log.d(TAG, "Cancelled WidgetUpdater"); } } @@ -281,7 +281,7 @@ public class PlaybackServiceTaskManager { Runnable chapterLoader = new Runnable() { @Override public void run() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Chapter loader started"); if (media.getChapters() == null) { media.loadChapterMarks(); @@ -289,7 +289,7 @@ public class PlaybackServiceTaskManager { callback.onChapterLoaded(media); } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Chapter loader stopped"); } }; @@ -335,7 +335,7 @@ public class PlaybackServiceTaskManager { @Override public void run() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting"); while (waitingTime > 0) { try { @@ -343,7 +343,7 @@ public class PlaybackServiceTaskManager { waitingTime -= UPDATE_INTERVALL; if (waitingTime <= 0) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Waiting completed"); postExecute(); if (!Thread.currentThread().isInterrupted()) { diff --git a/src/de/danoeh/antennapod/service/playback/PlayerWidgetService.java b/src/de/danoeh/antennapod/service/playback/PlayerWidgetService.java index 90ad7a9fa..71bc40c2a 100644 --- a/src/de/danoeh/antennapod/service/playback/PlayerWidgetService.java +++ b/src/de/danoeh/antennapod/service/playback/PlayerWidgetService.java @@ -12,7 +12,7 @@ import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.widget.RemoteViews; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.receiver.MediaButtonReceiver; import de.danoeh.antennapod.receiver.PlayerWidget; @@ -33,7 +33,7 @@ public class PlayerWidgetService extends Service { @Override public void onCreate() { super.onCreate(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Service created"); isUpdating = false; } @@ -41,7 +41,7 @@ public class PlayerWidgetService extends Service { @Override public void onDestroy() { super.onDestroy(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Service is about to be destroyed"); try { unbindService(mConnection); @@ -65,7 +65,7 @@ public class PlayerWidgetService extends Service { startViewUpdaterIfNotRunning(); } } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Service was called while updating. Ignoring update request"); } @@ -146,7 +146,7 @@ public class PlayerWidgetService extends Service { private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Connection to service established"); playbackService = ((PlaybackService.LocalBinder) service) .getService(); @@ -156,7 +156,7 @@ public class PlayerWidgetService extends Service { @Override public void onServiceDisconnected(ComponentName name) { playbackService = null; - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Disconnected from service"); } diff --git a/src/de/danoeh/antennapod/spa/SPAUtil.java b/src/de/danoeh/antennapod/spa/SPAUtil.java new file mode 100644 index 000000000..0d83741ed --- /dev/null +++ b/src/de/danoeh/antennapod/spa/SPAUtil.java @@ -0,0 +1,66 @@ +package de.danoeh.antennapod.spa; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; +import de.danoeh.antennapod.receiver.SPAReceiver; + +/** + * Provides methods related to AntennaPodSP (https://github.com/danieloeh/AntennaPodSP) + */ +public class SPAUtil { + private static final String TAG = "SPAUtil"; + + private static final String PREF_HAS_QUERIED_SP_APPS = "prefSPAUtil.hasQueriedSPApps"; + + private SPAUtil() { + } + + + /** + * Sends an ACTION_SP_APPS_QUERY_FEEDS intent to all AntennaPod Single Purpose apps. + * The receiving single purpose apps will then send their feeds back to AntennaPod via an + * ACTION_SP_APPS_QUERY_FEEDS_RESPONSE intent. + * This intent will only be sent once. + * + * @return True if an intent was sent, false otherwise (for example if the intent has already been + * sent before. + */ + public static synchronized boolean sendSPAppsQueryFeedsIntent(Context context) { + if (context == null) throw new IllegalArgumentException("context = null"); + final Context appContext = context.getApplicationContext(); + if (appContext == null) { + Log.wtf(TAG, "Unable to get application context"); + return false; + } + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext); + if (!prefs.getBoolean(PREF_HAS_QUERIED_SP_APPS, false)) { + appContext.sendBroadcast(new Intent(SPAReceiver.ACTION_SP_APPS_QUERY_FEEDS)); + if (BuildConfig.DEBUG) Log.d(TAG, "Sending SP_APPS_QUERY_FEEDS intent"); + + SharedPreferences.Editor editor = prefs.edit(); + editor.putBoolean(PREF_HAS_QUERIED_SP_APPS, true); + editor.commit(); + + return true; + } else { + return false; + } + } + + /** + * Resets all preferences created by this class. Should only be used for debug purposes. + */ + public static void resetSPAPreferences(Context c) { + if (BuildConfig.DEBUG) { + if (c == null) throw new IllegalArgumentException("c = null"); + SharedPreferences.Editor editor = PreferenceManager + .getDefaultSharedPreferences(c.getApplicationContext()).edit(); + editor.putBoolean(PREF_HAS_QUERIED_SP_APPS, false); + editor.commit(); + } + } +} diff --git a/src/de/danoeh/antennapod/storage/DBReader.java b/src/de/danoeh/antennapod/storage/DBReader.java index ccbf6646f..8d4785bd4 100644 --- a/src/de/danoeh/antennapod/storage/DBReader.java +++ b/src/de/danoeh/antennapod/storage/DBReader.java @@ -4,15 +4,15 @@ import android.content.Context; import android.database.Cursor; import android.database.SQLException; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.*; import de.danoeh.antennapod.service.download.DownloadStatus; import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.comparator.DownloadStatusComparator; import de.danoeh.antennapod.util.comparator.FeedItemPubdateComparator; +import de.danoeh.antennapod.util.comparator.PlaybackCompletionDateComparator; import de.danoeh.antennapod.util.flattr.FlattrStatus; import de.danoeh.antennapod.util.flattr.FlattrThing; -import de.danoeh.antennapod.util.comparator.PlaybackCompletionDateComparator; import java.util.ArrayList; import java.util.Collections; @@ -51,7 +51,7 @@ public final class DBReader { * can be loaded separately with {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.feed.Feed)}. */ public static List<Feed> getFeedList(final Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Extracting Feedlist"); PodDBAdapter adapter = new PodDBAdapter(context); @@ -103,7 +103,7 @@ public final class DBReader { * can be loaded separately with {@link #getFeedItemList(android.content.Context, de.danoeh.antennapod.feed.Feed)}. */ public static List<Feed> getExpiredFeedsList(final Context context, final long expirationTime) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, String.format("getExpiredFeedsList(%d)", expirationTime)); PodDBAdapter adapter = new PodDBAdapter(context); @@ -157,7 +157,7 @@ public final class DBReader { */ public static List<FeedItem> getFeedItemList(Context context, final Feed feed) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Extracting Feeditems of feed " + feed.getTitle()); PodDBAdapter adapter = new PodDBAdapter(context); @@ -216,7 +216,12 @@ public final class DBReader { .getString(PodDBAdapter.IDX_FI_SMALL_ITEM_IDENTIFIER)); item.setFlattrStatus(new FlattrStatus(itemlistCursor .getLong(PodDBAdapter.IDX_FI_SMALL_FLATTR_STATUS))); - + + long imageIndex = itemlistCursor.getLong(PodDBAdapter.IDX_FI_SMALL_IMAGE); + if (imageIndex != 0) { + item.setImage(getFeedImage(adapter, imageIndex)); + } + // extract chapters boolean hasSimpleChapters = itemlistCursor .getInt(PodDBAdapter.IDX_FI_SMALL_HAS_CHAPTERS) > 0; @@ -340,11 +345,13 @@ public final class DBReader { new FlattrStatus(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_FLATTR_STATUS))); if (image != null) { - image.setFeed(feed); + image.setOwner(feed); } FeedPreferences preferences = new FeedPreferences(cursor.getLong(PodDBAdapter.IDX_FEED_SEL_STD_ID), - cursor.getInt(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD) > 0); + cursor.getInt(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD) > 0, + cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_USERNAME), + cursor.getString(PodDBAdapter.IDX_FEED_SEL_PREFERENCES_PASSWORD)); feed.setPreferences(preferences); return feed; @@ -361,7 +368,7 @@ public final class DBReader { } static List<FeedItem> getQueue(Context context, PodDBAdapter adapter) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Extracting queue"); Cursor itemlistCursor = adapter.getQueueCursor(); @@ -414,7 +421,7 @@ public final class DBReader { * list in a {@link de.danoeh.antennapod.util.QueueAccess} object for easier access to the queue's properties. */ public static List<FeedItem> getQueue(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Extracting queue"); PodDBAdapter adapter = new PodDBAdapter(context); @@ -431,7 +438,7 @@ public final class DBReader { * @return A list of FeedItems whose episdoe has been downloaded. */ public static List<FeedItem> getDownloadedItems(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Extracting downloaded items"); PodDBAdapter adapter = new PodDBAdapter(context); @@ -457,7 +464,7 @@ public final class DBReader { * consider using {@link #getUnreadItemIds(android.content.Context)} instead. */ public static List<FeedItem> getUnreadItemsList(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Extracting unread items list"); PodDBAdapter adapter = new PodDBAdapter(context); @@ -506,7 +513,7 @@ public final class DBReader { * The size of the returned list is limited by {@link #PLAYBACK_HISTORY_SIZE}. */ public static List<FeedItem> getPlaybackHistory(final Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading playback history"); final int PLAYBACK_HISTORY_SIZE = 50; @@ -537,7 +544,7 @@ public final class DBReader { * The size of the returned list is limited by {@link #DOWNLOAD_LOG_SIZE}. */ public static List<DownloadStatus> getDownloadLog(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Extracting DownloadLog"); PodDBAdapter adapter = new PodDBAdapter(context); @@ -612,7 +619,7 @@ public final class DBReader { * database and the items-attribute will be set correctly. */ public static Feed getFeed(final Context context, final long feedId) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading feed with id " + feedId); Feed feed = null; @@ -631,7 +638,7 @@ public final class DBReader { } static FeedItem getFeedItem(final Context context, final long itemId, PodDBAdapter adapter) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading feeditem with id " + itemId); FeedItem item = null; @@ -656,7 +663,7 @@ public final class DBReader { * also be loaded from the database. */ public static FeedItem getFeedItem(final Context context, final long itemId) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Loading feeditem with id " + itemId); PodDBAdapter adapter = new PodDBAdapter(context); @@ -738,7 +745,7 @@ public final class DBReader { * @return The found object */ static FeedImage getFeedImage(PodDBAdapter adapter, final long id) { - Cursor cursor = adapter.getImageOfFeedCursor(id); + Cursor cursor = adapter.getImageCursor(id); if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { throw new SQLException("No FeedImage found at index: " + id); } diff --git a/src/de/danoeh/antennapod/storage/DBTasks.java b/src/de/danoeh/antennapod/storage/DBTasks.java index a583d07f4..92efeea62 100644 --- a/src/de/danoeh/antennapod/storage/DBTasks.java +++ b/src/de/danoeh/antennapod/storage/DBTasks.java @@ -4,7 +4,7 @@ import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.asynctask.FlattrClickWorker; import de.danoeh.antennapod.asynctask.FlattrStatusFetcher; import de.danoeh.antennapod.feed.*; @@ -155,10 +155,10 @@ public final class DBTasks { isRefreshing.set(false); if (FlattrUtils.hasToken()) { - if (AppConfig.DEBUG) Log.d(TAG, "Flattring all pending things."); + if (BuildConfig.DEBUG) Log.d(TAG, "Flattring all pending things."); new FlattrClickWorker(context, FlattrClickWorker.FLATTR_NOTIFICATION).executeAsync(); // flattr pending things - if (AppConfig.DEBUG) Log.d(TAG, "Fetching flattr status."); + if (BuildConfig.DEBUG) Log.d(TAG, "Fetching flattr status."); new FlattrStatusFetcher(context).start(); } @@ -167,7 +167,7 @@ public final class DBTasks { } }.start(); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Ignoring request to refresh all feeds: Refresh lock is locked"); } @@ -205,7 +205,7 @@ public final class DBTasks { * @param context Used for DB access. */ public static void refreshExpiredFeeds(final Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Refreshing expired feeds"); new Thread() { @@ -242,8 +242,15 @@ public final class DBTasks { */ public static void refreshFeed(Context context, Feed feed) throws DownloadRequestException { - DownloadRequester.getInstance().downloadFeed(context, - new Feed(feed.getDownload_url(), new Date(), feed.getTitle())); + Feed f; + if (feed.getPreferences() == null) { + f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle()); + } else { + f = new Feed(feed.getDownload_url(), new Date(), feed.getTitle(), + feed.getPreferences().getUsername(), feed.getPreferences().getPassword()); + } + + DownloadRequester.getInstance().downloadFeed(context, f); } /** @@ -381,7 +388,7 @@ public final class DBTasks { return autodownloadExec.submit(new Runnable() { @Override public void run() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Performing auto-dl of undownloaded episodes"); if (NetworkUtils.autodownloadNetworkAvailable(context) && UserPreferences.isEnableAutodownload()) { @@ -435,7 +442,7 @@ public final class DBTasks { } } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Enqueueing " + itemsToDownload.size() + " items for download"); @@ -530,7 +537,7 @@ public final class DBTasks { int counter = delete.size(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, String.format( "Auto-delete deleted %d episodes (%d requested)", counter, episodeNumber)); @@ -628,7 +635,7 @@ public final class DBTasks { final Feed savedFeed = searchFeedByIdentifyingValue(context, newFeed.getIdentifyingValue()); if (savedFeed == null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Found no existing Feed with title " + newFeed.getTitle() + ". Adding as new one."); @@ -642,18 +649,23 @@ public final class DBTasks { } return newFeed; } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Feed with title " + newFeed.getTitle() + " already exists. Syncing new with existing one."); Collections.sort(newFeed.getItems(), new FeedItemPubdateComparator()); savedFeed.setItems(DBReader.getFeedItemList(context, savedFeed)); if (savedFeed.compareWithOther(newFeed)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Feed has updated attribute values. Updating old feed's attributes"); savedFeed.updateFromOther(newFeed); } + if (savedFeed.getPreferences().compareWithOther(newFeed.getPreferences())) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Feed has updated preferences. Updating old feed's preferences"); + savedFeed.getPreferences().updateFromOther(newFeed.getPreferences()); + } // Look for new or updated Items for (int idx = 0; idx < newFeed.getItems().size(); idx++) { final FeedItem item = newFeed.getItems().get(idx); diff --git a/src/de/danoeh/antennapod/storage/DBWriter.java b/src/de/danoeh/antennapod/storage/DBWriter.java index 444e9ea0c..c1ce9da36 100644 --- a/src/de/danoeh/antennapod/storage/DBWriter.java +++ b/src/de/danoeh/antennapod/storage/DBWriter.java @@ -6,7 +6,7 @@ import android.content.SharedPreferences; import android.database.Cursor; import android.preference.PreferenceManager; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.asynctask.FlattrClickWorker; import de.danoeh.antennapod.feed.*; import de.danoeh.antennapod.preferences.GpodnetPreferences; @@ -110,7 +110,7 @@ public class DBWriter { } } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Deleting File. Result: " + result); EventDistributor.getInstance().sendQueueUpdateBroadcast(); EventDistributor.getInstance().sendUnreadItemsUpdateBroadcast(); @@ -176,6 +176,16 @@ public class DBWriter { && requester.isDownloadingFile(item.getMedia())) { requester.cancelDownload(context, item.getMedia()); } + + if (item.hasItemImage()) { + FeedImage image = item.getImage(); + if (image.isDownloaded() && image.getFile_url() != null) { + File imgFile = new File(image.getFile_url()); + imgFile.delete(); + } else if (requester.isDownloadingFile(image)) { + requester.cancelDownload(context, item.getImage()); + } + } } PodDBAdapter adapter = new PodDBAdapter(context); adapter.open(); @@ -225,7 +235,7 @@ public class DBWriter { return dbExec.submit(new Runnable() { @Override public void run() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Adding new item to playback history"); media.setPlaybackCompletionDate(new Date()); // reset played_duration to 0 so that it behaves correctly when the episode is played again @@ -244,7 +254,7 @@ public class DBWriter { private static void cleanupDownloadLog(final PodDBAdapter adapter) { final long logSize = adapter.getDownloadLogSize(); if (logSize > DBReader.DOWNLOAD_LOG_SIZE) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Cleaning up download log"); adapter.removeDownloadLogItems(logSize - DBReader.DOWNLOAD_LOG_SIZE); } @@ -797,7 +807,7 @@ public class DBWriter { PodDBAdapter adapter = new PodDBAdapter(context); adapter.open(); for (String key : urls.keySet()) { - if (AppConfig.DEBUG) Log.d(TAG, "Replacing URL " + key + " with url " + urls.get(key)); + if (BuildConfig.DEBUG) Log.d(TAG, "Replacing URL " + key + " with url " + urls.get(key)); adapter.setFeedDownloadUrl(key, urls.get(key)); } diff --git a/src/de/danoeh/antennapod/storage/DownloadRequester.java b/src/de/danoeh/antennapod/storage/DownloadRequester.java index 013162f0c..0a1747253 100644 --- a/src/de/danoeh/antennapod/storage/DownloadRequester.java +++ b/src/de/danoeh/antennapod/storage/DownloadRequester.java @@ -1,28 +1,28 @@ package de.danoeh.antennapod.storage; -import java.io.File; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.StringUtils; - import android.content.Context; import android.content.Intent; import android.util.Log; import android.webkit.URLUtil; -import de.danoeh.antennapod.AppConfig; -import de.danoeh.antennapod.feed.EventDistributor; -import de.danoeh.antennapod.feed.Feed; -import de.danoeh.antennapod.feed.FeedFile; -import de.danoeh.antennapod.feed.FeedImage; -import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.BuildConfig; +import de.danoeh.antennapod.feed.*; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.service.download.DownloadRequest; import de.danoeh.antennapod.service.download.DownloadService; import de.danoeh.antennapod.util.FileNameGenerator; import de.danoeh.antennapod.util.URLChecker; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; + +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Sends download requests to the DownloadService. This class should always be used for starting downloads, + * otherwise they won't work correctly. + */ public class DownloadRequester { private static final String TAG = "DownloadRequester"; @@ -45,15 +45,41 @@ public class DownloadRequester { return downloader; } + /** + * Starts a new download with the given DownloadRequest. This method should only + * be used from outside classes if the DownloadRequest was created by the DownloadService to + * ensure that the data is valid. Use downloadFeed(), downloadImage() or downloadMedia() instead. + * + * @param context Context object for starting the DownloadService + * @param request The DownloadRequest. If another DownloadRequest with the same source URL is already stored, this method + * call will return false. + * @return True if the download request was accepted, false otherwise. + */ + public boolean download(Context context, DownloadRequest request) { + if (context == null) throw new IllegalArgumentException("context = null"); + if (request == null) throw new IllegalArgumentException("request = null"); + if (downloads.containsKey(request.getSource())) { + if (BuildConfig.DEBUG) Log.i(TAG, "DownloadRequest is already stored."); + return false; + } + downloads.put(request.getSource(), request); + + Intent launchIntent = new Intent(context, DownloadService.class); + launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request); + context.startService(launchIntent); + EventDistributor.getInstance().sendDownloadQueuedBroadcast(); + return true; + } + private void download(Context context, FeedFile item, File dest, - boolean overwriteIfExists) { + boolean overwriteIfExists, String username, String password) { if (!isDownloadingFile(item)) { if (!isFilenameAvailable(dest.toString()) || dest.exists()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Filename already used."); if (isFilenameAvailable(dest.toString()) && overwriteIfExists) { boolean result = dest.delete(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Deleting file. Result: " + result); } else { // find different name @@ -65,12 +91,12 @@ public class DownloadRequester { + i + FilenameUtils.EXTENSION_SEPARATOR + FilenameUtils.getExtension(dest.getName()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Testing filename " + newName); newDest = new File(dest.getParent(), newName); if (!newDest.exists() && isFilenameAvailable(newDest.toString())) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "File doesn't exist yet. Using " + newName); break; @@ -81,21 +107,16 @@ public class DownloadRequester { } } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Requesting download of url " + item.getDownload_url()); item.setDownload_url(URLChecker.prepareURL(item.getDownload_url())); DownloadRequest request = new DownloadRequest(dest.toString(), item.getDownload_url(), item.getHumanReadableIdentifier(), - item.getId(), item.getTypeAsInt()); - - downloads.put(request.getSource(), request); + item.getId(), item.getTypeAsInt(), username, password); - Intent launchIntent = new Intent(context, DownloadService.class); - launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request); - context.startService(launchIntent); - EventDistributor.getInstance().sendDownloadQueuedBroadcast(); + download(context, request); } else { Log.e(TAG, "URL " + item.getDownload_url() + " is already being downloaded"); @@ -110,13 +131,13 @@ public class DownloadRequester { for (String key : downloads.keySet()) { DownloadRequest r = downloads.get(key); if (StringUtils.equals(r.getDestination(), path)) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, path + " is already used by another requested download"); return false; } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, path + " is available as a download destination"); return true; } @@ -124,8 +145,11 @@ public class DownloadRequester { public void downloadFeed(Context context, Feed feed) throws DownloadRequestException { if (feedFileValid(feed)) { + String username = (feed.getPreferences() != null) ? feed.getPreferences().getUsername() : null; + String password = (feed.getPreferences() != null) ? feed.getPreferences().getPassword() : null; + download(context, feed, new File(getFeedfilePath(context), - getFeedfileName(feed)), true); + getFeedfileName(feed)), true, username, password); } } @@ -133,7 +157,7 @@ public class DownloadRequester { throws DownloadRequestException { if (feedFileValid(image)) { download(context, image, new File(getImagefilePath(context), - getImagefileName(image)), true); + getImagefileName(image)), false, null, null); } } @@ -142,7 +166,8 @@ public class DownloadRequester { if (feedFileValid(feedmedia)) { download(context, feedmedia, new File(getMediafilePath(context, feedmedia), - getMediafilename(feedmedia)), false); + getMediafilename(feedmedia)), false, null, null + ); } } @@ -173,7 +198,7 @@ public class DownloadRequester { * Cancels a running download. */ public void cancelDownload(final Context context, final String downloadUrl) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Cancelling download with url " + downloadUrl); Intent cancelIntent = new Intent(DownloadService.ACTION_CANCEL_DOWNLOAD); cancelIntent.putExtra(DownloadService.EXTRA_DOWNLOAD_URL, downloadUrl); @@ -184,7 +209,7 @@ public class DownloadRequester { * Cancels all running downloads */ public void cancelAllDownloads(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Cancelling all running downloads"); context.sendBroadcast(new Intent( DownloadService.ACTION_CANCEL_ALL_DOWNLOADS)); @@ -266,8 +291,8 @@ public class DownloadRequester { public String getImagefileName(FeedImage image) { String filename = image.getDownload_url(); - if (image.getFeed() != null && image.getFeed().getTitle() != null) { - filename = image.getFeed().getTitle(); + if (image.getOwner() != null && image.getOwner().getHumanReadableIdentifier() != null) { + filename = image.getOwner().getHumanReadableIdentifier(); } return "image-" + FileNameGenerator.generateFileName(filename); } @@ -278,7 +303,8 @@ public class DownloadRequester { context, MEDIA_DOWNLOADPATH + FileNameGenerator.generateFileName(media.getItem() - .getFeed().getTitle()) + "/"); + .getFeed().getTitle()) + "/" + ); return externalStorage.toString(); } @@ -305,7 +331,8 @@ public class DownloadRequester { } String URLBaseFilename = URLUtil.guessFileName(media.getDownload_url(), - null, media.getMime_type());; + null, media.getMime_type()); + ; if (titleBaseFilename != "") { // Append extension diff --git a/src/de/danoeh/antennapod/storage/PodDBAdapter.java b/src/de/danoeh/antennapod/storage/PodDBAdapter.java index b44883744..825b5ac30 100644 --- a/src/de/danoeh/antennapod/storage/PodDBAdapter.java +++ b/src/de/danoeh/antennapod/storage/PodDBAdapter.java @@ -10,7 +10,7 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.*; import de.danoeh.antennapod.service.download.DownloadStatus; import de.danoeh.antennapod.util.flattr.FlattrStatus; @@ -25,7 +25,7 @@ import java.util.List; */ public class PodDBAdapter { private static final String TAG = "PodDBAdapter"; - private static final int DATABASE_VERSION = 11; + private static final int DATABASE_VERSION = 12; public static final String DATABASE_NAME = "Antennapod.db"; /** @@ -56,6 +56,8 @@ public class PodDBAdapter { public static final int KEY_TYPE_INDEX = 12; public static final int KEY_FEED_IDENTIFIER_INDEX = 13; public static final int KEY_FEED_FLATTR_STATUS_INDEX = 14; + public static final int KEY_FEED_USERNAME_INDEX = 15; + public static final int KEY_FEED_PASSWORD_INDEX = 16; // ----------- FeedItem indices public static final int KEY_CONTENT_ENCODED_INDEX = 2; public static final int KEY_PUBDATE_INDEX = 3; @@ -131,6 +133,8 @@ public class PodDBAdapter { public static final String KEY_PLAYBACK_COMPLETION_DATE = "playback_completion_date"; public static final String KEY_AUTO_DOWNLOAD = "auto_download"; public static final String KEY_PLAYED_DURATION = "played_duration"; + public static final String KEY_USERNAME = "username"; + public static final String KEY_PASSWORD = "password"; // Table names public static final String TABLE_NAME_FEEDS = "Feeds"; @@ -153,7 +157,9 @@ public class PodDBAdapter { + KEY_LASTUPDATE + " TEXT," + KEY_LANGUAGE + " TEXT," + KEY_AUTHOR + " TEXT," + KEY_IMAGE + " INTEGER," + KEY_TYPE + " TEXT," + KEY_FEED_IDENTIFIER + " TEXT," + KEY_AUTO_DOWNLOAD + " INTEGER DEFAULT 1," - + KEY_FLATTR_STATUS + " INTEGER)"; + + KEY_FLATTR_STATUS + " INTEGER," + + KEY_USERNAME + " TEXT," + + KEY_PASSWORD + " TEXT)"; private static final String CREATE_TABLE_FEED_ITEMS = "CREATE TABLE " + TABLE_NAME_FEED_ITEMS + " (" + TABLE_PRIMARY_KEY + KEY_TITLE @@ -162,7 +168,8 @@ public class PodDBAdapter { + KEY_DESCRIPTION + " TEXT," + KEY_PAYMENT_LINK + " TEXT," + KEY_MEDIA + " INTEGER," + KEY_FEED + " INTEGER," + KEY_HAS_CHAPTERS + " INTEGER," + KEY_ITEM_IDENTIFIER + " TEXT," - + KEY_FLATTR_STATUS + " INTEGER)"; + + KEY_FLATTR_STATUS + " INTEGER," + + KEY_IMAGE + " INTEGER)"; private static final String CREATE_TABLE_FEED_IMAGES = "CREATE TABLE " + TABLE_NAME_FEED_IMAGES + " (" + TABLE_PRIMARY_KEY + KEY_TITLE @@ -217,7 +224,9 @@ public class PodDBAdapter { TABLE_NAME_FEEDS + "." + KEY_TYPE, TABLE_NAME_FEEDS + "." + KEY_FEED_IDENTIFIER, TABLE_NAME_FEEDS + "." + KEY_AUTO_DOWNLOAD, - TABLE_NAME_FEEDS + "." + KEY_FLATTR_STATUS + TABLE_NAME_FEEDS + "." + KEY_FLATTR_STATUS, + TABLE_NAME_FEEDS + "." + KEY_USERNAME, + TABLE_NAME_FEEDS + "." + KEY_PASSWORD }; // column indices for FEED_SEL_STD @@ -237,6 +246,8 @@ public class PodDBAdapter { public static final int IDX_FEED_SEL_STD_FEED_IDENTIFIER = 13; public static final int IDX_FEED_SEL_PREFERENCES_AUTO_DOWNLOAD = 14; public static final int IDX_FEED_SEL_STD_FLATTR_STATUS = 15; + public static final int IDX_FEED_SEL_PREFERENCES_USERNAME = 16; + public static final int IDX_FEED_SEL_PREFERENCES_PASSWORD = 17; /** @@ -253,7 +264,8 @@ public class PodDBAdapter { TABLE_NAME_FEED_ITEMS + "." + KEY_FEED, TABLE_NAME_FEED_ITEMS + "." + KEY_HAS_CHAPTERS, TABLE_NAME_FEED_ITEMS + "." + KEY_ITEM_IDENTIFIER, - TABLE_NAME_FEED_ITEMS + "." + KEY_FLATTR_STATUS}; + TABLE_NAME_FEED_ITEMS + "." + KEY_FLATTR_STATUS, + TABLE_NAME_FEED_ITEMS + "." + KEY_IMAGE}; /** * Contains FEEDITEM_SEL_FI_SMALL as comma-separated list. Useful for raw queries. @@ -278,6 +290,7 @@ public class PodDBAdapter { public static final int IDX_FI_SMALL_HAS_CHAPTERS = 8; public static final int IDX_FI_SMALL_ITEM_IDENTIFIER = 9; public static final int IDX_FI_SMALL_FLATTR_STATUS = 10; + public static final int IDX_FI_SMALL_IMAGE = 11; /** * Select id, description and content-encoded column from feeditems. @@ -308,7 +321,7 @@ public class PodDBAdapter { public PodDBAdapter open() { if (db == null || !db.isOpen() || db.isReadOnly()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Opening DB"); try { db = helper.getWritableDatabase(); @@ -321,7 +334,7 @@ public class PodDBAdapter { } public void close() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Closing DB"); //db.close(); } @@ -365,11 +378,11 @@ public class PodDBAdapter { values.put(KEY_FLATTR_STATUS, feed.getFlattrStatus().toLong()); if (feed.getId() == 0) { // Create new entry - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(this.toString(), "Inserting new Feed into db"); feed.setId(db.insert(TABLE_NAME_FEEDS, null, values)); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(this.toString(), "Updating existing Feed in db"); db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(feed.getId())}); @@ -383,6 +396,8 @@ public class PodDBAdapter { } ContentValues values = new ContentValues(); values.put(KEY_AUTO_DOWNLOAD, prefs.getAutoDownload()); + values.put(KEY_USERNAME, prefs.getUsername()); + values.put(KEY_PASSWORD, prefs.getPassword()); db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(prefs.getFeedID())}); } @@ -404,10 +419,14 @@ public class PodDBAdapter { db.update(TABLE_NAME_FEED_IMAGES, values, KEY_ID + "=?", new String[]{String.valueOf(image.getId())}); } - if (image.getFeed() != null && image.getFeed().getId() != 0) { + + final FeedComponent owner = image.getOwner(); + if (owner != null && owner.getId() != 0) { values.clear(); values.put(KEY_IMAGE, image.getId()); - db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getFeed().getId())}); + if (owner instanceof Feed) { + db.update(TABLE_NAME_FEEDS, values, KEY_ID + "=?", new String[]{String.valueOf(image.getOwner().getId())}); + } } db.setTransactionSuccessful(); db.endTransaction(); @@ -484,6 +503,9 @@ public class PodDBAdapter { setFeedItem(item, false); } } + if (feed.getPreferences() != null) { + setFeedPreferences(feed.getPreferences()); + } db.setTransactionSuccessful(); db.endTransaction(); } @@ -502,7 +524,7 @@ public class PodDBAdapter { */ public Cursor getFeedsInFlattrQueueCursor() { return db.query(TABLE_NAME_FEEDS, FEED_SEL_STD, KEY_FLATTR_STATUS + "=?", - new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)},null, null, null); + new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)}, null, null, null); } /** @@ -510,7 +532,7 @@ public class PodDBAdapter { */ public Cursor getFeedItemsInFlattrQueueCursor() { return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FLATTR_STATUS + "=?", - new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)},null, null, null); + new String[]{String.valueOf(FlattrStatus.STATUS_QUEUE)}, null, null, null); } /** @@ -577,8 +599,7 @@ public class PodDBAdapter { * Update the flattr status of a feed or feed item specified by its payment link * and the new flattr status to use */ - public void setItemFlattrStatus(String url, FlattrStatus status) - { + public void setItemFlattrStatus(String url, FlattrStatus status) { //Log.d(TAG, "setItemFlattrStatus(" + url + ") = " + status.toString()); ContentValues values = new ContentValues(); values.put(KEY_FLATTR_STATUS, status.toLong()); @@ -593,19 +614,19 @@ public class PodDBAdapter { if (db.update(TABLE_NAME_FEEDS, values, KEY_PAYMENT_LINK + " GLOB ?" - + " OR " + KEY_PAYMENT_LINK + " GLOB ?" - + " OR " + KEY_PAYMENT_LINK + " GLOB ?" - + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls) > 0) - { + + " OR " + KEY_PAYMENT_LINK + " GLOB ?" + + " OR " + KEY_PAYMENT_LINK + " GLOB ?" + + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls + ) > 0) { Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in Feeds table"); return; } if (db.update(TABLE_NAME_FEED_ITEMS, values, KEY_PAYMENT_LINK + " GLOB ?" - + " OR " + KEY_PAYMENT_LINK + " GLOB ?" - + " OR " + KEY_PAYMENT_LINK + " GLOB ?" - + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls) > 0) - { + + " OR " + KEY_PAYMENT_LINK + " GLOB ?" + + " OR " + KEY_PAYMENT_LINK + " GLOB ?" + + " OR " + KEY_PAYMENT_LINK + " GLOB ?", query_urls + ) > 0) { Log.i(TAG, "setItemFlattrStatus found match for " + url + " = " + status.toLong() + " in FeedsItems table"); } } @@ -613,8 +634,7 @@ public class PodDBAdapter { /** * Reset flattr status to unflattrd for all items */ - public void clearAllFlattrStatus() - { + public void clearAllFlattrStatus() { ContentValues values = new ContentValues(); values.put(KEY_FLATTR_STATUS, 0); db.update(TABLE_NAME_FEEDS, values, null, null); @@ -649,6 +669,13 @@ public class PodDBAdapter { values.put(KEY_HAS_CHAPTERS, item.getChapters() != null); values.put(KEY_ITEM_IDENTIFIER, item.getItemIdentifier()); values.put(KEY_FLATTR_STATUS, item.getFlattrStatus().toLong()); + if (item.hasItemImage()) { + if (item.getImage().getId() == 0) { + setImage(item.getImage()); + } + values.put(KEY_IMAGE, item.getImage().getId()); + } + if (item.getId() == 0) { item.setId(db.insert(TABLE_NAME_FEED_ITEMS, null, values)); } else { @@ -797,6 +824,9 @@ public class PodDBAdapter { if (item.getChapters() != null) { removeChaptersOfItem(item); } + if (item.hasItemImage()) { + removeFeedImage(item.getImage()); + } db.delete(TABLE_NAME_FEED_ITEMS, KEY_ID + "=?", new String[]{String.valueOf(item.getId())}); } @@ -865,8 +895,9 @@ public class PodDBAdapter { public final Cursor getAllItemsOfFeedCursor(final long feedId) { Cursor c = db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED - + "=?", new String[]{String.valueOf(feedId)}, null, null, - null); + + "=?", new String[]{String.valueOf(feedId)}, null, null, + null + ); return c; } @@ -900,7 +931,7 @@ public class PodDBAdapter { * @param id ID of the FeedImage * @return The cursor of the query */ - public final Cursor getImageOfFeedCursor(final long id) { + public final Cursor getImageCursor(final long id) { Cursor c = db.query(TABLE_NAME_FEED_IMAGES, null, KEY_ID + "=?", new String[]{String.valueOf(id)}, null, null, null); return c; @@ -908,8 +939,9 @@ public class PodDBAdapter { public final Cursor getSimpleChaptersOfFeedItemCursor(final FeedItem item) { Cursor c = db.query(TABLE_NAME_SIMPLECHAPTERS, null, KEY_FEEDITEM - + "=?", new String[]{String.valueOf(item.getId())}, null, - null, null); + + "=?", new String[]{String.valueOf(item.getId())}, null, + null, null + ); return c; } @@ -1056,7 +1088,8 @@ public class PodDBAdapter { if (ids.length > IN_OPERATOR_MAXIMUM) { throw new IllegalArgumentException( "number of IDs must not be larger than " - + IN_OPERATOR_MAXIMUM); + + IN_OPERATOR_MAXIMUM + ); } return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_ID + " IN " @@ -1111,15 +1144,17 @@ public class PodDBAdapter { if (feedID != 0) { // search items in specific feed return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED - + "=? AND " + KEY_DESCRIPTION + " LIKE '%" - + prepareSearchQuery(query) + "%'", + + "=? AND " + KEY_DESCRIPTION + " LIKE '%" + + prepareSearchQuery(query) + "%'", new String[]{String.valueOf(feedID)}, null, null, - null); + null + ); } else { // search through all items return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_DESCRIPTION + " LIKE '%" + prepareSearchQuery(query) - + "%'", null, null, null, null); + + "%'", null, null, null, null + ); } } @@ -1133,16 +1168,18 @@ public class PodDBAdapter { if (feedID != 0) { // search items in specific feed return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED - + "=? AND " + KEY_CONTENT_ENCODED + " LIKE '%" - + prepareSearchQuery(query) + "%'", + + "=? AND " + KEY_CONTENT_ENCODED + " LIKE '%" + + prepareSearchQuery(query) + "%'", new String[]{String.valueOf(feedID)}, null, null, - null); + null + ); } else { // search through all items return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_CONTENT_ENCODED + " LIKE '%" + prepareSearchQuery(query) + "%'", null, null, - null, null); + null, null + ); } } @@ -1150,16 +1187,18 @@ public class PodDBAdapter { if (feedID != 0) { // search items in specific feed return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_FEED - + "=? AND " + KEY_TITLE + " LIKE '%" - + prepareSearchQuery(query) + "%'", + + "=? AND " + KEY_TITLE + " LIKE '%" + + prepareSearchQuery(query) + "%'", new String[]{String.valueOf(feedID)}, null, null, - null); + null + ); } else { // search through all items return db.query(TABLE_NAME_FEED_ITEMS, FEEDITEM_SEL_FI_SMALL, KEY_TITLE + " LIKE '%" + prepareSearchQuery(query) + "%'", null, null, - null, null); + null, null + ); } } @@ -1308,6 +1347,17 @@ public class PodDBAdapter { + " ADD COLUMN " + KEY_PLAYED_DURATION + " INTEGER"); } + if (oldVersion <= 11) { + db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_USERNAME + + " TEXT"); + db.execSQL("ALTER TABLE " + TABLE_NAME_FEEDS + + " ADD COLUMN " + KEY_PASSWORD + + " TEXT"); + db.execSQL("ALTER TABLE " + TABLE_NAME_FEED_ITEMS + + " ADD COLUMN " + KEY_IMAGE + + " INTEGER"); + } } } } diff --git a/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java b/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java index 9b25d16c4..5576603b6 100644 --- a/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java +++ b/src/de/danoeh/antennapod/syndication/handler/FeedHandler.java @@ -1,18 +1,16 @@ package de.danoeh.antennapod.syndication.handler; -import java.io.File; -import java.io.IOException; -import java.io.Reader; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - +import de.danoeh.antennapod.feed.Feed; import org.apache.commons.io.input.XmlStreamReader; import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import de.danoeh.antennapod.feed.Feed; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.File; +import java.io.IOException; +import java.io.Reader; public class FeedHandler { diff --git a/src/de/danoeh/antennapod/syndication/handler/HandlerState.java b/src/de/danoeh/antennapod/syndication/handler/HandlerState.java index e8687858b..a9a8bb934 100644 --- a/src/de/danoeh/antennapod/syndication/handler/HandlerState.java +++ b/src/de/danoeh/antennapod/syndication/handler/HandlerState.java @@ -1,14 +1,14 @@ package de.danoeh.antennapod.syndication.handler; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Stack; - import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.syndication.namespace.Namespace; import de.danoeh.antennapod.syndication.namespace.SyndElement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Stack; + /** * Contains all relevant information to describe the current state of a * SyndHandler. diff --git a/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java b/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java index c51d054d4..15dc94d65 100644 --- a/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java +++ b/src/de/danoeh/antennapod/syndication/handler/SyndHandler.java @@ -1,20 +1,13 @@ package de.danoeh.antennapod.syndication.handler; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.Feed; -import de.danoeh.antennapod.syndication.namespace.NSContent; -import de.danoeh.antennapod.syndication.namespace.NSITunes; -import de.danoeh.antennapod.syndication.namespace.NSMedia; -import de.danoeh.antennapod.syndication.namespace.NSRSS20; -import de.danoeh.antennapod.syndication.namespace.NSSimpleChapters; -import de.danoeh.antennapod.syndication.namespace.Namespace; -import de.danoeh.antennapod.syndication.namespace.SyndElement; +import de.danoeh.antennapod.syndication.namespace.*; import de.danoeh.antennapod.syndication.namespace.atom.NSAtom; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; /** Superclass for all SAX Handlers which process Syndication formats */ public class SyndHandler extends DefaultHandler { @@ -84,28 +77,28 @@ public class SyndHandler extends DefaultHandler { state.defaultNamespaces.push(new NSAtom()); } else if (prefix.equals(NSAtom.NSTAG)) { state.namespaces.put(uri, new NSAtom()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized Atom namespace"); } } else if (uri.equals(NSContent.NSURI) && prefix.equals(NSContent.NSTAG)) { state.namespaces.put(uri, new NSContent()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized Content namespace"); } else if (uri.equals(NSITunes.NSURI) && prefix.equals(NSITunes.NSTAG)) { state.namespaces.put(uri, new NSITunes()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized ITunes namespace"); } else if (uri.equals(NSSimpleChapters.NSURI) && prefix.matches(NSSimpleChapters.NSTAG)) { state.namespaces.put(uri, new NSSimpleChapters()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized SimpleChapters namespace"); } else if (uri.equals(NSMedia.NSURI) && prefix.equals(NSMedia.NSTAG)) { state.namespaces.put(uri, new NSMedia()); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized media namespace"); } } diff --git a/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java b/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java index d2454f2b9..0ac1b7ae2 100644 --- a/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java +++ b/src/de/danoeh/antennapod/syndication/handler/TypeGetter.java @@ -1,18 +1,17 @@ package de.danoeh.antennapod.syndication.handler; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.Reader; - +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; +import de.danoeh.antennapod.feed.Feed; import org.apache.commons.io.input.XmlStreamReader; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; -import de.danoeh.antennapod.feed.Feed; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Reader; /** Gets the type of a specific feed by reading the root element. */ public class TypeGetter { @@ -40,7 +39,7 @@ public class TypeGetter { String tag = xpp.getName(); if (tag.equals(ATOM_ROOT)) { feed.setType(Feed.TYPE_ATOM1); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized type Atom"); return Type.ATOM; } else if (tag.equals(RSS_ROOT)) { @@ -50,12 +49,12 @@ public class TypeGetter { if (strVersion.equals("2.0")) { feed.setType(Feed.TYPE_RSS2); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized type RSS 2.0"); return Type.RSS20; } else if (strVersion.equals("0.91") || strVersion.equals("0.92")) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Recognized type RSS 0.91/0.92"); return Type.RSS091; @@ -63,7 +62,7 @@ public class TypeGetter { } throw new UnsupportedFeedtypeException(Type.INVALID); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Type is invalid"); throw new UnsupportedFeedtypeException(Type.INVALID); } @@ -78,7 +77,7 @@ public class TypeGetter { e.printStackTrace(); } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Type is invalid"); throw new UnsupportedFeedtypeException(Type.INVALID); } diff --git a/src/de/danoeh/antennapod/syndication/namespace/NSContent.java b/src/de/danoeh/antennapod/syndication/namespace/NSContent.java index 7f2a3e87d..9ad3026be 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/NSContent.java +++ b/src/de/danoeh/antennapod/syndication/namespace/NSContent.java @@ -1,8 +1,7 @@ package de.danoeh.antennapod.syndication.namespace; -import org.xml.sax.Attributes; - import de.danoeh.antennapod.syndication.handler.HandlerState; +import org.xml.sax.Attributes; public class NSContent extends Namespace { public static final String NSTAG = "content"; diff --git a/src/de/danoeh/antennapod/syndication/namespace/NSITunes.java b/src/de/danoeh/antennapod/syndication/namespace/NSITunes.java index cd7fef509..d8cbe040b 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/NSITunes.java +++ b/src/de/danoeh/antennapod/syndication/namespace/NSITunes.java @@ -1,40 +1,51 @@ package de.danoeh.antennapod.syndication.namespace; -import org.xml.sax.Attributes; - import de.danoeh.antennapod.feed.FeedImage; import de.danoeh.antennapod.syndication.handler.HandlerState; +import org.xml.sax.Attributes; + +public class NSITunes extends Namespace { + public static final String NSTAG = "itunes"; + public static final String NSURI = "http://www.itunes.com/dtds/podcast-1.0.dtd"; + + private static final String IMAGE = "image"; + private static final String IMAGE_TITLE = "image"; + private static final String IMAGE_HREF = "href"; + + private static final String AUTHOR = "author"; + + + @Override + public SyndElement handleElementStart(String localName, HandlerState state, + Attributes attributes) { + if (localName.equals(IMAGE)) { + FeedImage image = new FeedImage(); + image.setTitle(IMAGE_TITLE); + image.setDownload_url(attributes.getValue(IMAGE_HREF)); + + if (state.getCurrentItem() != null) { + // this is an items image + image.setTitle(state.getCurrentItem().getTitle() + IMAGE_TITLE); + state.getCurrentItem().setImage(image); + + } else { + // this is the feed image + if (state.getFeed().getImage() == null) { + state.getFeed().setImage(image); + } + } + + } + + return new SyndElement(localName, this); + } + + @Override + public void handleElementEnd(String localName, HandlerState state) { + if (localName.equals(AUTHOR)) { + state.getFeed().setAuthor(state.getContentBuf().toString()); + } -public class NSITunes extends Namespace{ - public static final String NSTAG = "itunes"; - public static final String NSURI = "http://www.itunes.com/dtds/podcast-1.0.dtd"; - - private static final String IMAGE = "image"; - private static final String IMAGE_TITLE = "image"; - private static final String IMAGE_HREF = "href"; - - private static final String AUTHOR = "author"; - - - @Override - public SyndElement handleElementStart(String localName, HandlerState state, - Attributes attributes) { - if (localName.equals(IMAGE) && state.getFeed().getImage() == null) { - FeedImage image = new FeedImage(); - image.setTitle(IMAGE_TITLE); - image.setDownload_url(attributes.getValue(IMAGE_HREF)); - state.getFeed().setImage(image); - } - - return new SyndElement(localName, this); - } - - @Override - public void handleElementEnd(String localName, HandlerState state) { - if (localName.equals(AUTHOR)) { - state.getFeed().setAuthor(state.getContentBuf().toString()); - } - - } + } } diff --git a/src/de/danoeh/antennapod/syndication/namespace/NSMedia.java b/src/de/danoeh/antennapod/syndication/namespace/NSMedia.java index 053a81270..cc23167c1 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/NSMedia.java +++ b/src/de/danoeh/antennapod/syndication/namespace/NSMedia.java @@ -1,14 +1,13 @@ package de.danoeh.antennapod.syndication.namespace; -import java.util.concurrent.TimeUnit; - -import org.xml.sax.Attributes; - import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.syndication.handler.HandlerState; import de.danoeh.antennapod.syndication.util.SyndTypeUtils; +import org.xml.sax.Attributes; + +import java.util.concurrent.TimeUnit; /** Processes tags from the http://search.yahoo.com/mrss/ namespace. */ public class NSMedia extends Namespace { @@ -38,7 +37,7 @@ public class NSMedia extends Namespace { try { size = Long.parseLong(attributes.getValue(SIZE)); } catch (NumberFormatException e) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Length attribute could not be parsed."); } @@ -50,7 +49,7 @@ public class NSMedia extends Namespace { Long.parseLong(durationStr), TimeUnit.SECONDS); } } catch (NumberFormatException e) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Duration attribute could not be parsed"); } diff --git a/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java b/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java index 3eb49172d..9572f87ae 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java +++ b/src/de/danoeh/antennapod/syndication/namespace/NSRSS20.java @@ -1,15 +1,14 @@ package de.danoeh.antennapod.syndication.namespace; -import org.xml.sax.Attributes; - import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.FeedImage; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.syndication.handler.HandlerState; import de.danoeh.antennapod.syndication.util.SyndDateUtils; import de.danoeh.antennapod.syndication.util.SyndTypeUtils; +import org.xml.sax.Attributes; /** * SAX-Parser for reading RSS-Feeds @@ -57,7 +56,7 @@ public class NSRSS20 extends Namespace { try { size = Long.parseLong(attributes.getValue(ENC_LEN)); } catch (NumberFormatException e) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Length attribute could not be parsed."); } state.getCurrentItem().setMedia( diff --git a/src/de/danoeh/antennapod/syndication/namespace/NSSimpleChapters.java b/src/de/danoeh/antennapod/syndication/namespace/NSSimpleChapters.java index 55c26e812..3f983ee88 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/NSSimpleChapters.java +++ b/src/de/danoeh/antennapod/syndication/namespace/NSSimpleChapters.java @@ -1,13 +1,12 @@ package de.danoeh.antennapod.syndication.namespace; -import java.util.ArrayList; - -import org.xml.sax.Attributes; - import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.SimpleChapter; import de.danoeh.antennapod.syndication.handler.HandlerState; import de.danoeh.antennapod.syndication.util.SyndDateUtils; +import org.xml.sax.Attributes; + +import java.util.ArrayList; public class NSSimpleChapters extends Namespace { public static final String NSTAG = "psc|sc"; diff --git a/src/de/danoeh/antennapod/syndication/namespace/Namespace.java b/src/de/danoeh/antennapod/syndication/namespace/Namespace.java index 9eafef71e..910131feb 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/Namespace.java +++ b/src/de/danoeh/antennapod/syndication/namespace/Namespace.java @@ -1,8 +1,7 @@ package de.danoeh.antennapod.syndication.namespace; -import org.xml.sax.Attributes; - import de.danoeh.antennapod.syndication.handler.HandlerState; +import org.xml.sax.Attributes; public abstract class Namespace { diff --git a/src/de/danoeh/antennapod/syndication/namespace/atom/AtomText.java b/src/de/danoeh/antennapod/syndication/namespace/atom/AtomText.java index fec20de2f..86b80d2ed 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/atom/AtomText.java +++ b/src/de/danoeh/antennapod/syndication/namespace/atom/AtomText.java @@ -1,9 +1,8 @@ package de.danoeh.antennapod.syndication.namespace.atom; -import org.apache.commons.lang3.StringEscapeUtils; - import de.danoeh.antennapod.syndication.namespace.Namespace; import de.danoeh.antennapod.syndication.namespace.SyndElement; +import org.apache.commons.lang3.StringEscapeUtils; /** Represents Atom Element which contains text (content, title, summary). */ public class AtomText extends SyndElement { diff --git a/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java b/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java index bc68d6f6a..383b29fc8 100644 --- a/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java +++ b/src/de/danoeh/antennapod/syndication/namespace/atom/NSAtom.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.syndication.namespace.atom; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.FeedImage; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.feed.FeedMedia; @@ -84,7 +84,7 @@ public class NSAtom extends Namespace { size = Long.parseLong(strSize); } } catch (NumberFormatException e) { - if (AppConfig.DEBUG) Log.d(TAG, "Length attribute could not be parsed."); + if (BuildConfig.DEBUG) Log.d(TAG, "Length attribute could not be parsed."); } String type = attributes.getValue(LINK_TYPE); if (SyndTypeUtils.enclosureTypeValid(type) diff --git a/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java b/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java index a1ed01354..2c1cff914 100644 --- a/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java +++ b/src/de/danoeh/antennapod/syndication/util/SyndDateUtils.java @@ -1,12 +1,12 @@ package de.danoeh.antennapod.syndication.util; +import android.util.Log; + import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; -import android.util.Log; - /** Parses several date formats. */ public class SyndDateUtils { private static final String TAG = "DateUtils"; diff --git a/src/de/danoeh/antennapod/syndication/util/SyndTypeUtils.java b/src/de/danoeh/antennapod/syndication/util/SyndTypeUtils.java index fe7836d37..d0fa3a5fc 100644 --- a/src/de/danoeh/antennapod/syndication/util/SyndTypeUtils.java +++ b/src/de/danoeh/antennapod/syndication/util/SyndTypeUtils.java @@ -1,8 +1,7 @@ package de.danoeh.antennapod.syndication.util; -import org.apache.commons.io.FilenameUtils; - import android.webkit.MimeTypeMap; +import org.apache.commons.io.FilenameUtils; /** Utility class for handling MIME-Types of enclosures */ public class SyndTypeUtils { diff --git a/src/de/danoeh/antennapod/util/BitmapDecoder.java b/src/de/danoeh/antennapod/util/BitmapDecoder.java index e9423c3f7..5296d675a 100644 --- a/src/de/danoeh/antennapod/util/BitmapDecoder.java +++ b/src/de/danoeh/antennapod/util/BitmapDecoder.java @@ -1,15 +1,14 @@ package de.danoeh.antennapod.util; -import java.io.InputStream; - -import org.apache.commons.io.IOUtils; - import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.asynctask.ImageLoader; +import org.apache.commons.io.IOUtils; + +import java.io.InputStream; public class BitmapDecoder { private static final String TAG = "BitmapDecoder"; @@ -33,7 +32,7 @@ public class BitmapDecoder { int srcHeight = options.outHeight; int length = Math.max(srcWidth, srcHeight); int sampleSize = calculateSampleSize(preferredLength, length); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Using samplesize " + sampleSize); options.inJustDecodeBounds = false; options.inSampleSize = sampleSize; diff --git a/src/de/danoeh/antennapod/util/ChapterUtils.java b/src/de/danoeh/antennapod/util/ChapterUtils.java index 521bfebea..9e1c50674 100644 --- a/src/de/danoeh/antennapod/util/ChapterUtils.java +++ b/src/de/danoeh/antennapod/util/ChapterUtils.java @@ -1,20 +1,7 @@ package de.danoeh.antennapod.util; -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Collections; -import java.util.List; - -import org.apache.commons.io.IOUtils; - import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.util.comparator.ChapterStartTimeComparator; import de.danoeh.antennapod.util.id3reader.ChapterReader; @@ -22,6 +9,13 @@ import de.danoeh.antennapod.util.id3reader.ID3ReaderException; import de.danoeh.antennapod.util.playback.Playable; import de.danoeh.antennapod.util.vorbiscommentreader.VorbisCommentChapterReader; import de.danoeh.antennapod.util.vorbiscommentreader.VorbisCommentReaderException; +import org.apache.commons.io.IOUtils; + +import java.io.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.List; /** Utility class for getting chapter data from media files. */ public class ChapterUtils { @@ -36,7 +30,7 @@ public class ChapterUtils { */ public static void readID3ChaptersFromPlayableStreamUrl(Playable p) { if (p != null && p.getStreamUrl() != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle()); InputStream in = null; try { @@ -87,7 +81,7 @@ public class ChapterUtils { */ public static void readID3ChaptersFromPlayableFileUrl(Playable p) { if (p != null && p.localFileAvailable() && p.getLocalMediaUrl() != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Reading id3 chapters from item " + p.getEpisodeTitle()); File source = new File(p.getLocalMediaUrl()); if (source.exists()) { @@ -170,7 +164,7 @@ public class ChapterUtils { private static void readOggChaptersFromInputStream(Playable p, InputStream input) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Trying to read chapters from item with title " + p.getEpisodeTitle()); @@ -243,14 +237,14 @@ public class ChapterUtils { } public static void loadChaptersFromStreamUrl(Playable media) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Starting chapterLoader thread"); ChapterUtils.readID3ChaptersFromPlayableStreamUrl(media); if (media.getChapters() == null) { ChapterUtils.readOggChaptersFromPlayableStreamUrl(media); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "ChapterLoaderThread has finished"); } diff --git a/src/de/danoeh/antennapod/util/ConnectionTester.java b/src/de/danoeh/antennapod/util/ConnectionTester.java deleted file mode 100644 index 5d940d9e1..000000000 --- a/src/de/danoeh/antennapod/util/ConnectionTester.java +++ /dev/null @@ -1,78 +0,0 @@ -package de.danoeh.antennapod.util; - -import java.io.IOException; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; - -import android.os.Handler; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; - -/** Tests a connection before downloading something. */ -public class ConnectionTester implements Runnable { - private static final String TAG = "ConnectionTester"; - private String strUrl; - private Callback callback; - private DownloadError reason; - - private Handler handler; - - public ConnectionTester(String url, Callback callback) { - super(); - this.strUrl = url; - this.callback = callback; - this.handler = new Handler(); - } - - @Override - public void run() { - if (AppConfig.DEBUG) - Log.d(TAG, "Testing connection"); - try { - URL url = new URL(strUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.connect(); - handler.post(new Runnable() { - @Override - public void run() { - callback.onConnectionSuccessful(); - } - }); if (AppConfig.DEBUG) - Log.d(TAG, "Connection seems to work"); - } catch (MalformedURLException e) { - e.printStackTrace(); - reason = DownloadError.ERROR_CONNECTION_ERROR; - if (AppConfig.DEBUG) - Log.d(TAG, "Connection failed"); - handler.post(new Runnable() { - @Override - public void run() { - callback.onConnectionFailure(reason); - } - }); - } catch (IOException e) { - e.printStackTrace(); - reason = DownloadError.ERROR_CONNECTION_ERROR; - if (AppConfig.DEBUG) - Log.d(TAG, "Connection failed"); - handler.post(new Runnable() { - @Override - public void run() { - callback.onConnectionFailure(reason); - } - }); - } - } - - public static abstract class Callback { - public abstract void onConnectionSuccessful(); - - public abstract void onConnectionFailure(DownloadError reason); - } - - public DownloadError getReason() { - return reason; - } - -} diff --git a/src/de/danoeh/antennapod/util/DownloadError.java b/src/de/danoeh/antennapod/util/DownloadError.java index f7a5c23fe..1a64991a6 100644 --- a/src/de/danoeh/antennapod/util/DownloadError.java +++ b/src/de/danoeh/antennapod/util/DownloadError.java @@ -18,7 +18,8 @@ public enum DownloadError { ERROR_NOT_ENOUGH_SPACE(10, R.string.download_error_insufficient_space), ERROR_UNKNOWN_HOST(11, R.string.download_error_unknown_host), ERROR_REQUEST_ERROR(12, R.string.download_error_request_error), - ERROR_DB_ACCESS_ERROR(13, R.string.download_error_db_access); + ERROR_DB_ACCESS_ERROR(13, R.string.download_error_db_access), + ERROR_UNAUTHORIZED(14, R.string.download_error_unauthorized); private final int code; private final int resId; diff --git a/src/de/danoeh/antennapod/util/EpisodeFilter.java b/src/de/danoeh/antennapod/util/EpisodeFilter.java index ee627b161..115913bca 100644 --- a/src/de/danoeh/antennapod/util/EpisodeFilter.java +++ b/src/de/danoeh/antennapod/util/EpisodeFilter.java @@ -1,10 +1,10 @@ package de.danoeh.antennapod.util; +import de.danoeh.antennapod.feed.FeedItem; + import java.util.ArrayList; import java.util.List; -import de.danoeh.antennapod.feed.FeedItem; - public class EpisodeFilter { private EpisodeFilter() { diff --git a/src/de/danoeh/antennapod/util/FeedtitleComparator.java b/src/de/danoeh/antennapod/util/FeedtitleComparator.java index e334268b1..112b6678d 100644 --- a/src/de/danoeh/antennapod/util/FeedtitleComparator.java +++ b/src/de/danoeh/antennapod/util/FeedtitleComparator.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.util; -import java.util.Comparator; - import de.danoeh.antennapod.feed.Feed; +import java.util.Comparator; + /** Compares the title of two feeds for sorting. */ public class FeedtitleComparator implements Comparator<Feed> { diff --git a/src/de/danoeh/antennapod/util/NetworkUtils.java b/src/de/danoeh/antennapod/util/NetworkUtils.java index 278f7ad7a..0c8065e94 100644 --- a/src/de/danoeh/antennapod/util/NetworkUtils.java +++ b/src/de/danoeh/antennapod/util/NetworkUtils.java @@ -1,17 +1,17 @@ package de.danoeh.antennapod.util; -import java.util.Arrays; -import java.util.List; - import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.preferences.UserPreferences; +import java.util.Arrays; +import java.util.List; + public class NetworkUtils { private static final String TAG = "NetworkUtils"; @@ -31,11 +31,11 @@ public class NetworkUtils { NetworkInfo networkInfo = cm.getActiveNetworkInfo(); if (networkInfo != null) { if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Device is connected to Wi-Fi"); if (networkInfo.isConnected()) { if (!UserPreferences.isEnableAutodownloadWifiFilter()) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Auto-dl filter is disabled"); return true; } else { @@ -47,7 +47,7 @@ public class NetworkUtils { .getAutodownloadSelectedNetworks()); if (selectedNetworks.contains(Integer.toString(wifiInfo .getNetworkId()))) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Current network is on the selected networks list"); return true; @@ -56,7 +56,7 @@ public class NetworkUtils { } } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Network for auto-dl is not available"); return false; } diff --git a/src/de/danoeh/antennapod/util/ShownotesProvider.java b/src/de/danoeh/antennapod/util/ShownotesProvider.java index d273e0b8f..8345ca34d 100644 --- a/src/de/danoeh/antennapod/util/ShownotesProvider.java +++ b/src/de/danoeh/antennapod/util/ShownotesProvider.java @@ -1,7 +1,6 @@ package de.danoeh.antennapod.util; import java.util.concurrent.Callable; -import java.util.concurrent.FutureTask; /** * Created by daniel on 04.08.13. diff --git a/src/de/danoeh/antennapod/util/StorageUtils.java b/src/de/danoeh/antennapod/util/StorageUtils.java index 52a12f6a6..ff0bde280 100644 --- a/src/de/danoeh/antennapod/util/StorageUtils.java +++ b/src/de/danoeh/antennapod/util/StorageUtils.java @@ -1,18 +1,18 @@ package de.danoeh.antennapod.util; -import java.io.File; - import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.StatFs; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.activity.StorageErrorActivity; import de.danoeh.antennapod.preferences.UserPreferences; +import java.io.File; + /** Utility functions for handling storage errors */ public class StorageUtils { private static final String TAG = "StorageUtils"; @@ -22,7 +22,7 @@ public class StorageUtils { if (dir != null) { return dir.exists() && dir.canRead() && dir.canWrite(); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Storage not available: data folder is null"); return false; } diff --git a/src/de/danoeh/antennapod/util/URIUtil.java b/src/de/danoeh/antennapod/util/URIUtil.java new file mode 100644 index 000000000..5af40d591 --- /dev/null +++ b/src/de/danoeh/antennapod/util/URIUtil.java @@ -0,0 +1,35 @@ +package de.danoeh.antennapod.util; + +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; + +/** + * Utility methods for dealing with URL encoding. + */ +public class URIUtil { + private static final String TAG = "URIUtil"; + + private URIUtil() {} + + public static URI getURIFromRequestUrl(String source) { + // try without encoding the URI + try { + return new URI(source); + } catch (URISyntaxException e) { + if (BuildConfig.DEBUG) Log.d(TAG, "Source is not encoded, encoding now"); + } + try { + URL url = new URL(source); + return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef()); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e); + } + } +} diff --git a/src/de/danoeh/antennapod/util/URLChecker.java b/src/de/danoeh/antennapod/util/URLChecker.java index 13668d4a9..a3c675899 100644 --- a/src/de/danoeh/antennapod/util/URLChecker.java +++ b/src/de/danoeh/antennapod/util/URLChecker.java @@ -1,7 +1,7 @@ package de.danoeh.antennapod.util; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; /** Provides methods for checking and editing a URL.*/ public final class URLChecker { @@ -20,10 +20,10 @@ public final class URLChecker { public static String prepareURL(String url) { StringBuilder builder = new StringBuilder(); if (url.startsWith("feed://")) { - if (AppConfig.DEBUG) Log.d(TAG, "Replacing feed:// with http://"); + if (BuildConfig.DEBUG) Log.d(TAG, "Replacing feed:// with http://"); url = url.replace("feed://", "http://"); } else if (!(url.startsWith("http://") || url.startsWith("https://"))) { - if (AppConfig.DEBUG) Log.d(TAG, "Adding http:// at the beginning of the URL"); + if (BuildConfig.DEBUG) Log.d(TAG, "Adding http:// at the beginning of the URL"); builder.append("http://"); } builder.append(url); diff --git a/src/de/danoeh/antennapod/util/UndoBarController.java b/src/de/danoeh/antennapod/util/UndoBarController.java index a0240e7ce..332cc22e0 100644 --- a/src/de/danoeh/antennapod/util/UndoBarController.java +++ b/src/de/danoeh/antennapod/util/UndoBarController.java @@ -26,10 +26,10 @@ import com.nineoldandroids.animation.Animator; import com.nineoldandroids.animation.AnimatorListenerAdapter; import com.nineoldandroids.view.ViewHelper; import com.nineoldandroids.view.ViewPropertyAnimator; -import static com.nineoldandroids.view.ViewPropertyAnimator.animate; - import de.danoeh.antennapod.R; +import static com.nineoldandroids.view.ViewPropertyAnimator.animate; + public class UndoBarController { private View mBarView; private TextView mMessageView; diff --git a/src/de/danoeh/antennapod/util/comparator/ChapterStartTimeComparator.java b/src/de/danoeh/antennapod/util/comparator/ChapterStartTimeComparator.java index 7cc6fa458..bfc2fd057 100644 --- a/src/de/danoeh/antennapod/util/comparator/ChapterStartTimeComparator.java +++ b/src/de/danoeh/antennapod/util/comparator/ChapterStartTimeComparator.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.util.comparator; -import java.util.Comparator; - import de.danoeh.antennapod.feed.Chapter; +import java.util.Comparator; + public class ChapterStartTimeComparator implements Comparator<Chapter> { @Override diff --git a/src/de/danoeh/antennapod/util/comparator/DownloadStatusComparator.java b/src/de/danoeh/antennapod/util/comparator/DownloadStatusComparator.java index d0561252f..14b8f1194 100644 --- a/src/de/danoeh/antennapod/util/comparator/DownloadStatusComparator.java +++ b/src/de/danoeh/antennapod/util/comparator/DownloadStatusComparator.java @@ -1,8 +1,8 @@ package de.danoeh.antennapod.util.comparator; -import java.util.Comparator; +import de.danoeh.antennapod.service.download.DownloadStatus; -import de.danoeh.antennapod.service.download.*; +import java.util.Comparator; /** Compares the completion date of two Downloadstatus objects. */ public class DownloadStatusComparator implements Comparator<DownloadStatus> { diff --git a/src/de/danoeh/antennapod/util/comparator/FeedItemPubdateComparator.java b/src/de/danoeh/antennapod/util/comparator/FeedItemPubdateComparator.java index c95c0833c..f92c23d05 100644 --- a/src/de/danoeh/antennapod/util/comparator/FeedItemPubdateComparator.java +++ b/src/de/danoeh/antennapod/util/comparator/FeedItemPubdateComparator.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.util.comparator; -import java.util.Comparator; - import de.danoeh.antennapod.feed.FeedItem; +import java.util.Comparator; + /** Compares the pubDate of two FeedItems for sorting*/ public class FeedItemPubdateComparator implements Comparator<FeedItem> { diff --git a/src/de/danoeh/antennapod/util/comparator/PlaybackCompletionDateComparator.java b/src/de/danoeh/antennapod/util/comparator/PlaybackCompletionDateComparator.java index 434a5a956..0147e0cdc 100644 --- a/src/de/danoeh/antennapod/util/comparator/PlaybackCompletionDateComparator.java +++ b/src/de/danoeh/antennapod/util/comparator/PlaybackCompletionDateComparator.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.util.comparator; -import java.util.Comparator; - import de.danoeh.antennapod.feed.FeedItem; +import java.util.Comparator; + public class PlaybackCompletionDateComparator implements Comparator<FeedItem> { public int compare(FeedItem lhs, FeedItem rhs) { diff --git a/src/de/danoeh/antennapod/util/comparator/SearchResultValueComparator.java b/src/de/danoeh/antennapod/util/comparator/SearchResultValueComparator.java index ab7d47673..02b084a01 100644 --- a/src/de/danoeh/antennapod/util/comparator/SearchResultValueComparator.java +++ b/src/de/danoeh/antennapod/util/comparator/SearchResultValueComparator.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.util.comparator; -import java.util.Comparator; - import de.danoeh.antennapod.feed.SearchResult; +import java.util.Comparator; + public class SearchResultValueComparator implements Comparator<SearchResult> { @Override diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrServiceCreator.java b/src/de/danoeh/antennapod/util/flattr/FlattrServiceCreator.java index b7e77e158..eda83b7aa 100644 --- a/src/de/danoeh/antennapod/util/flattr/FlattrServiceCreator.java +++ b/src/de/danoeh/antennapod/util/flattr/FlattrServiceCreator.java @@ -1,12 +1,11 @@ package de.danoeh.antennapod.util.flattr; +import android.util.Log; +import de.danoeh.antennapod.BuildConfig; import org.shredzone.flattr4j.FlattrFactory; import org.shredzone.flattr4j.FlattrService; import org.shredzone.flattr4j.oauth.AccessToken; -import android.util.Log; -import de.danoeh.antennapod.AppConfig; - /** Ensures that only one instance of the FlattrService class exists at a time */ public class FlattrServiceCreator { @@ -19,7 +18,7 @@ public class FlattrServiceCreator { } public static void deleteFlattrService() { - if (AppConfig.DEBUG) Log.d(TAG, "Deleting service instance"); + if (BuildConfig.DEBUG) Log.d(TAG, "Deleting service instance"); flattrService = null; } } diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrThing.java b/src/de/danoeh/antennapod/util/flattr/FlattrThing.java index 872132517..f17ef1d83 100644 --- a/src/de/danoeh/antennapod/util/flattr/FlattrThing.java +++ b/src/de/danoeh/antennapod/util/flattr/FlattrThing.java @@ -1,7 +1,5 @@ package de.danoeh.antennapod.util.flattr; -import de.danoeh.antennapod.util.flattr.FlattrStatus; - public interface FlattrThing { public String getTitle(); public String getPaymentLink(); diff --git a/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java b/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java index 423e98891..9809f69a3 100644 --- a/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java +++ b/src/de/danoeh/antennapod/util/flattr/FlattrUtils.java @@ -1,21 +1,5 @@ package de.danoeh.antennapod.util.flattr; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.EnumSet; -import java.util.List; -import java.util.ListIterator; -import java.util.TimeZone; - -import org.shredzone.flattr4j.FlattrService; -import org.shredzone.flattr4j.exception.FlattrException; -import org.shredzone.flattr4j.model.Flattr; -import org.shredzone.flattr4j.model.Thing; -import org.shredzone.flattr4j.oauth.AccessToken; -import org.shredzone.flattr4j.oauth.AndroidAuthenticator; -import org.shredzone.flattr4j.oauth.Scope; - import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; @@ -25,12 +9,21 @@ import android.content.SharedPreferences; import android.net.Uri; import android.preference.PreferenceManager; import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.PodcastApp; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.FlattrAuthActivity; import de.danoeh.antennapod.asynctask.FlattrTokenFetcher; import de.danoeh.antennapod.storage.DBWriter; +import org.shredzone.flattr4j.FlattrService; +import org.shredzone.flattr4j.exception.FlattrException; +import org.shredzone.flattr4j.model.Flattr; +import org.shredzone.flattr4j.model.Thing; +import org.shredzone.flattr4j.oauth.AccessToken; +import org.shredzone.flattr4j.oauth.AndroidAuthenticator; +import org.shredzone.flattr4j.oauth.Scope; + +import java.util.*; /** Utility methods for doing something with flattr. */ @@ -63,17 +56,17 @@ public class FlattrUtils { private static AccessToken retrieveToken() { if (cachedToken == null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Retrieving access token"); String token = PreferenceManager.getDefaultSharedPreferences( PodcastApp.getInstance()) .getString(PREF_ACCESS_TOKEN, null); if (token != null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Found access token. Caching."); cachedToken = new AccessToken(token); } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "No access token found"); return null; } @@ -87,7 +80,7 @@ public class FlattrUtils { } public static void storeToken(AccessToken token) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Storing token"); SharedPreferences.Editor editor = PreferenceManager .getDefaultSharedPreferences(PodcastApp.getInstance()).edit(); @@ -101,7 +94,7 @@ public class FlattrUtils { } public static void deleteToken() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Deleting flattr token"); storeToken(null); } @@ -159,7 +152,7 @@ public class FlattrUtils { } } - if (AppConfig.DEBUG) { + if (BuildConfig.DEBUG) { Log.d(TAG, "Got my flattrs list of length " + Integer.toString(myFlattrs.size()) + " comparison date" + firstOfMonthDate); for (Flattr fl: myFlattrs) { @@ -181,7 +174,7 @@ public class FlattrUtils { } public static void revokeAccessToken(Context context) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Revoking access token"); deleteToken(); FlattrServiceCreator.deleteFlattrService(); @@ -206,7 +199,7 @@ public class FlattrUtils { } public static void showNoTokenDialog(final Context context, final String url) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Creating showNoTokenDialog"); AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.no_flattr_token_title); diff --git a/src/de/danoeh/antennapod/util/id3reader/ChapterReader.java b/src/de/danoeh/antennapod/util/id3reader/ChapterReader.java index f897f886c..257635129 100644 --- a/src/de/danoeh/antennapod/util/id3reader/ChapterReader.java +++ b/src/de/danoeh/antennapod/util/id3reader/ChapterReader.java @@ -1,19 +1,18 @@ package de.danoeh.antennapod.util.id3reader; -import java.io.IOException; -import java.io.InputStream; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.List; - import android.util.Log; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.ID3Chapter; import de.danoeh.antennapod.util.id3reader.model.FrameHeader; import de.danoeh.antennapod.util.id3reader.model.TagHeader; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.List; + public class ChapterReader extends ID3Reader { private static final String TAG = "ID3ChapterReader"; @@ -39,7 +38,7 @@ public class ChapterReader extends ID3Reader { if (currentChapter != null) { if (!hasId3Chapter(currentChapter)) { chapters.add(currentChapter); - if (AppConfig.DEBUG) Log.d(TAG, "Found chapter: " + currentChapter); + if (BuildConfig.DEBUG) Log.d(TAG, "Found chapter: " + currentChapter); currentChapter = null; } } @@ -58,7 +57,7 @@ public class ChapterReader extends ID3Reader { readString(title, input, header.getSize()); currentChapter .setTitle(title.toString()); - if (AppConfig.DEBUG) Log.d(TAG, "Found title: " + currentChapter.getTitle()); + if (BuildConfig.DEBUG) Log.d(TAG, "Found title: " + currentChapter.getTitle()); return ID3Reader.ACTION_DONT_SKIP; } @@ -72,7 +71,7 @@ public class ChapterReader extends ID3Reader { currentChapter.setLink(decodedLink); - if (AppConfig.DEBUG) Log.d(TAG, "Found link: " + currentChapter.getLink()); + if (BuildConfig.DEBUG) Log.d(TAG, "Found link: " + currentChapter.getLink()); return ID3Reader.ACTION_DONT_SKIP; } } else if (header.getId().equals("APIC")) { diff --git a/src/de/danoeh/antennapod/util/id3reader/ID3Reader.java b/src/de/danoeh/antennapod/util/id3reader/ID3Reader.java index 92f817363..252d64107 100644 --- a/src/de/danoeh/antennapod/util/id3reader/ID3Reader.java +++ b/src/de/danoeh/antennapod/util/id3reader/ID3Reader.java @@ -1,15 +1,14 @@ package de.danoeh.antennapod.util.id3reader; +import de.danoeh.antennapod.util.id3reader.model.FrameHeader; +import de.danoeh.antennapod.util.id3reader.model.TagHeader; +import org.apache.commons.io.IOUtils; + import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.charset.Charset; -import org.apache.commons.io.IOUtils; - -import de.danoeh.antennapod.util.id3reader.model.FrameHeader; -import de.danoeh.antennapod.util.id3reader.model.TagHeader; - /** * Reads the ID3 Tag of a given file. In order to use this class, you should * create a subclass of it and overwrite the onStart* - or onEnd* - methods. diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java index 615c1c93e..6733430da 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedItemMenuHandler.java @@ -3,7 +3,7 @@ package de.danoeh.antennapod.util.menuhandler; import android.content.Context; import android.content.Intent; import android.net.Uri; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.feed.FeedItem; import de.danoeh.antennapod.service.playback.PlaybackService; @@ -95,7 +95,7 @@ public class FeedItemMenuHandler { mi.setItemVisibility(R.id.share_link_item, false); } - if (!AppConfig.DEBUG + if (!BuildConfig.DEBUG || !(state == FeedItem.State.IN_PROGRESS || state == FeedItem.State.READ)) { mi.setItemVisibility(R.id.mark_unread_item, false); } diff --git a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java index 537335618..ae8b3ac1e 100644 --- a/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java +++ b/src/de/danoeh/antennapod/util/menuhandler/FeedMenuHandler.java @@ -4,18 +4,12 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.util.Log; - import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.activity.FeedInfoActivity; -import de.danoeh.antennapod.asynctask.FlattrClickWorker; import de.danoeh.antennapod.feed.Feed; import de.danoeh.antennapod.service.download.DownloadService; import de.danoeh.antennapod.storage.DBTasks; @@ -23,7 +17,6 @@ import de.danoeh.antennapod.storage.DBWriter; import de.danoeh.antennapod.storage.DownloadRequestException; import de.danoeh.antennapod.storage.DownloadRequester; import de.danoeh.antennapod.util.ShareUtils; -import de.danoeh.antennapod.util.flattr.FlattrStatus; /** Handles interactions with the FeedItemMenu. */ public class FeedMenuHandler { @@ -39,7 +32,7 @@ public class FeedMenuHandler { return true; } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Preparing options menu"); menu.findItem(R.id.mark_all_read_item).setVisible( selectedFeed.hasNewItems(true)); diff --git a/src/de/danoeh/antennapod/util/playback/AudioPlayer.java b/src/de/danoeh/antennapod/util/playback/AudioPlayer.java index 0945303e4..bd49b0d18 100644 --- a/src/de/danoeh/antennapod/util/playback/AudioPlayer.java +++ b/src/de/danoeh/antennapod/util/playback/AudioPlayer.java @@ -3,7 +3,6 @@ package de.danoeh.antennapod.util.playback; import android.content.Context; import android.util.Log; import android.view.SurfaceHolder; - import com.aocate.media.MediaPlayer; public class AudioPlayer extends MediaPlayer implements IPlayer { diff --git a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java index e937ee437..390498cea 100644 --- a/src/de/danoeh/antennapod/util/playback/ExternalMedia.java +++ b/src/de/danoeh/antennapod/util/playback/ExternalMedia.java @@ -1,9 +1,5 @@ package de.danoeh.antennapod.util.playback; -import java.io.InputStream; -import java.util.List; -import java.util.concurrent.Callable; - import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.media.MediaMetadataRetriever; @@ -13,6 +9,10 @@ import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.MediaType; import de.danoeh.antennapod.util.ChapterUtils; +import java.io.InputStream; +import java.util.List; +import java.util.concurrent.Callable; + /** Represents a media file that is stored on the local storage device. */ public class ExternalMedia implements Playable { diff --git a/src/de/danoeh/antennapod/util/playback/IPlayer.java b/src/de/danoeh/antennapod/util/playback/IPlayer.java index 8c1cf4ef4..99f53fb52 100644 --- a/src/de/danoeh/antennapod/util/playback/IPlayer.java +++ b/src/de/danoeh/antennapod/util/playback/IPlayer.java @@ -1,9 +1,9 @@ package de.danoeh.antennapod.util.playback; -import java.io.IOException; - import android.view.SurfaceHolder; +import java.io.IOException; + public interface IPlayer { boolean canSetPitch(); diff --git a/src/de/danoeh/antennapod/util/playback/Playable.java b/src/de/danoeh/antennapod/util/playback/Playable.java index 98d5fbb36..8eefb0be5 100644 --- a/src/de/danoeh/antennapod/util/playback/Playable.java +++ b/src/de/danoeh/antennapod/util/playback/Playable.java @@ -1,15 +1,6 @@ package de.danoeh.antennapod.util.playback; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.List; -import java.util.concurrent.FutureTask; - import android.content.Context; -import de.danoeh.antennapod.storage.DBReader; -import de.danoeh.antennapod.util.ShownotesProvider; -import org.apache.commons.io.IOUtils; - import android.content.SharedPreferences; import android.media.MediaMetadataRetriever; import android.os.Parcelable; @@ -18,6 +9,13 @@ import de.danoeh.antennapod.asynctask.ImageLoader; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.FeedMedia; import de.danoeh.antennapod.feed.MediaType; +import de.danoeh.antennapod.storage.DBReader; +import de.danoeh.antennapod.util.ShownotesProvider; +import org.apache.commons.io.IOUtils; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.List; /** * Interface for objects that can be played by the PlaybackService. diff --git a/src/de/danoeh/antennapod/util/playback/PlaybackController.java b/src/de/danoeh/antennapod/util/playback/PlaybackController.java index 0781800aa..1992fce2c 100644 --- a/src/de/danoeh/antennapod/util/playback/PlaybackController.java +++ b/src/de/danoeh/antennapod/util/playback/PlaybackController.java @@ -15,7 +15,7 @@ import android.view.View.OnClickListener; import android.widget.ImageButton; import android.widget.SeekBar; import android.widget.TextView; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.FeedMedia; @@ -114,7 +114,7 @@ public abstract class PlaybackController { * example in the activity's onStop() method. */ public void release() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Releasing PlaybackController"); try { @@ -160,7 +160,7 @@ public abstract class PlaybackController { * as the arguments of the launch intent. */ private void bindToService() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Trying to connect to service"); AsyncTask<Void, Void, Intent> intentLoader = new AsyncTask<Void, Void, Intent>() { @Override @@ -173,7 +173,7 @@ public abstract class PlaybackController { boolean bound = false; if (!PlaybackService.started) { if (serviceIntent != null) { - if (AppConfig.DEBUG) Log.d(TAG, "Calling start service"); + if (BuildConfig.DEBUG) Log.d(TAG, "Calling start service"); activity.startService(serviceIntent); bound = activity.bindService(serviceIntent, mConnection, 0); } else { @@ -182,13 +182,13 @@ public abstract class PlaybackController { handleStatus(); } } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "PlaybackService is running, trying to connect without start command."); bound = activity.bindService(new Intent(activity, PlaybackService.class), mConnection, 0); } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Result for service binding: " + bound); } }; @@ -200,7 +200,7 @@ public abstract class PlaybackController { * played media or null if no last played media could be found. */ private Intent getPlayLastPlayedMediaIntent() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Trying to restore last played media"); SharedPreferences prefs = PreferenceManager .getDefaultSharedPreferences(activity.getApplicationContext()); @@ -229,7 +229,7 @@ public abstract class PlaybackController { return serviceIntent; } } - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "No last played media found"); return null; } @@ -242,7 +242,7 @@ public abstract class PlaybackController { || (positionObserverFuture != null && positionObserverFuture .isDone()) || positionObserverFuture == null) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Setting up position observer"); positionObserver = new MediaPositionObserver(); positionObserverFuture = schedExecutor.scheduleWithFixedDelay( @@ -255,7 +255,7 @@ public abstract class PlaybackController { private void cancelPositionObserver() { if (positionObserverFuture != null) { boolean result = positionObserverFuture.cancel(true); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "PositionObserver cancelled. Result: " + result); } } @@ -268,7 +268,7 @@ public abstract class PlaybackController { .getService(); if (!released) { queryService(); - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Connection to Service established"); } else { Log.i(TAG, "Connection to playback service has been established, but controller has already been released"); @@ -278,7 +278,7 @@ public abstract class PlaybackController { @Override public void onServiceDisconnected(ComponentName name) { playbackService = null; - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Disconnected from Service"); } @@ -287,7 +287,7 @@ public abstract class PlaybackController { protected BroadcastReceiver statusUpdate = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Received statusUpdate Intent."); if (isConnectedToPlaybackService()) { PlaybackServiceMediaPlayer.PSMPInfo info = playbackService.getPSMPInfo(); @@ -345,7 +345,7 @@ public abstract class PlaybackController { } } else { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Bad arguments. Won't handle intent"); } } else { @@ -422,12 +422,16 @@ public abstract class PlaybackController { checkMediaInfoLoaded(); cancelPositionObserver(); updatePlayButtonAppearance(playResource, playText); + if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) { + setScreenOn(false); + } break; case PLAYING: clearStatusMsg(); checkMediaInfoLoaded(); if (PlaybackService.getCurrentMediaType() == MediaType.VIDEO) { onAwaitingVideoSurface(); + setScreenOn(true); } setupPositionObserver(); updatePlayButtonAppearance(pauseResource, pauseText); @@ -487,7 +491,7 @@ public abstract class PlaybackController { * information has to be refreshed */ void queryService() { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Querying service info"); if (playbackService != null) { status = playbackService.getStatus(); @@ -551,6 +555,16 @@ public abstract class PlaybackController { } } + /** + * Should be implemented by classes that show a video. The default implementation + * does nothing + * + * @param enable True if the screen should be kept on, false otherwise + */ + protected void setScreenOn(boolean enable) { + + } + public OnClickListener newOnPlayButtonClickListener() { return new OnClickListener() { @Override diff --git a/src/de/danoeh/antennapod/util/vorbiscommentreader/OggInputStream.java b/src/de/danoeh/antennapod/util/vorbiscommentreader/OggInputStream.java index c11125abf..767034ed2 100644 --- a/src/de/danoeh/antennapod/util/vorbiscommentreader/OggInputStream.java +++ b/src/de/danoeh/antennapod/util/vorbiscommentreader/OggInputStream.java @@ -1,10 +1,11 @@ package de.danoeh.antennapod.util.vorbiscommentreader; + +import org.apache.commons.io.IOUtils; + import java.io.IOException; import java.io.InputStream; import java.util.Arrays; -import org.apache.commons.io.IOUtils; - public class OggInputStream extends InputStream { private InputStream input; diff --git a/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentChapterReader.java b/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentChapterReader.java index c78977652..b2f149ddd 100644 --- a/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentChapterReader.java +++ b/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentChapterReader.java @@ -1,13 +1,13 @@ package de.danoeh.antennapod.util.vorbiscommentreader; -import java.util.ArrayList; -import java.util.List; - import android.util.Log; -import de.danoeh.antennapod.AppConfig; +import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.feed.Chapter; import de.danoeh.antennapod.feed.VorbisCommentChapter; +import java.util.ArrayList; +import java.util.List; + public class VorbisCommentChapterReader extends VorbisCommentReader { private static final String TAG = "VorbisCommentChapterReader"; @@ -39,7 +39,7 @@ public class VorbisCommentChapterReader extends VorbisCommentReader { @Override public void onContentVectorValue(String key, String value) throws VorbisCommentReaderException { - if (AppConfig.DEBUG) + if (BuildConfig.DEBUG) Log.d(TAG, "Key: " + key + ", value: " + value); String attribute = VorbisCommentChapter.getAttributeTypeFromKey(key); int id = VorbisCommentChapter.getIDFromKey(key); diff --git a/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentReader.java b/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentReader.java index 06a3911ab..718a4f30f 100644 --- a/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentReader.java +++ b/src/de/danoeh/antennapod/util/vorbiscommentreader/VorbisCommentReader.java @@ -1,5 +1,8 @@ package de.danoeh.antennapod.util.vorbiscommentreader; +import org.apache.commons.io.EndianUtils; +import org.apache.commons.io.IOUtils; + import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -7,9 +10,6 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.Arrays; -import org.apache.commons.io.EndianUtils; -import org.apache.commons.io.IOUtils; - public abstract class VorbisCommentReader { /** Length of first page in an ogg file in bytes. */ diff --git a/src/instrumentationTest/de/test/antennapod/AntennaPodTestRunner.java b/src/instrumentationTest/de/test/antennapod/AntennaPodTestRunner.java index e1699139d..35ecf86dc 100644 --- a/src/instrumentationTest/de/test/antennapod/AntennaPodTestRunner.java +++ b/src/instrumentationTest/de/test/antennapod/AntennaPodTestRunner.java @@ -12,7 +12,8 @@ public class AntennaPodTestRunner extends InstrumentationTestRunner { @Override public TestSuite getAllTests() { - return new TestSuiteBuilder(AntennaPodTestRunner.class).includeAllPackagesUnderHere() + return new TestSuiteBuilder(AntennaPodTestRunner.class).includePackages("instrumentationTest.de.test.antennapod.storage") + //.includeAllPackagesUnderHere() // .excludePackages("instrumentationTest.de.test.antennapod.syndication.handler") // .excludePackages("instrumentationTest.de.test.antennapod.gpodnet") .build(); diff --git a/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java b/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java index 679ae1ad3..67d99f9fc 100644 --- a/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java +++ b/src/instrumentationTest/de/test/antennapod/storage/DBWriterTest.java @@ -95,7 +95,7 @@ public class DBWriterTest extends InstrumentationTestCase { File imgFile = new File(destFolder, "image"); assertTrue(imgFile.createNewFile()); FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true); - image.setFeed(feed); + image.setOwner(feed); feed.setImage(image); List<File> itemFiles = new ArrayList<File>(); @@ -137,7 +137,7 @@ public class DBWriterTest extends InstrumentationTestCase { Cursor c = adapter.getFeedCursor(feed.getId()); assertTrue(c.getCount() == 0); c.close(); - c = adapter.getImageOfFeedCursor(image.getId()); + c = adapter.getImageCursor(image.getId()); assertTrue(c.getCount() == 0); c.close(); for (FeedItem item : feed.getItems()) { @@ -217,7 +217,7 @@ public class DBWriterTest extends InstrumentationTestCase { File imgFile = new File(destFolder, "image"); assertTrue(imgFile.createNewFile()); FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true); - image.setFeed(feed); + image.setOwner(feed); feed.setImage(image); PodDBAdapter adapter = new PodDBAdapter(getInstrumentation().getContext()); @@ -238,7 +238,7 @@ public class DBWriterTest extends InstrumentationTestCase { Cursor c = adapter.getFeedCursor(feed.getId()); assertTrue(c.getCount() == 0); c.close(); - c = adapter.getImageOfFeedCursor(image.getId()); + c = adapter.getImageCursor(image.getId()); assertTrue(c.getCount() == 0); c.close(); } @@ -254,7 +254,7 @@ public class DBWriterTest extends InstrumentationTestCase { File imgFile = new File(destFolder, "image"); assertTrue(imgFile.createNewFile()); FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true); - image.setFeed(feed); + image.setOwner(feed); feed.setImage(image); // create items @@ -285,7 +285,7 @@ public class DBWriterTest extends InstrumentationTestCase { Cursor c = adapter.getFeedCursor(feed.getId()); assertTrue(c.getCount() == 0); c.close(); - c = adapter.getImageOfFeedCursor(image.getId()); + c = adapter.getImageCursor(image.getId()); assertTrue(c.getCount() == 0); c.close(); for (FeedItem item : feed.getItems()) { @@ -295,6 +295,64 @@ public class DBWriterTest extends InstrumentationTestCase { } } + public void testDeleteFeedWithItemImages() throws InterruptedException, ExecutionException, TimeoutException, IOException { + File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); + assertNotNull(destFolder); + + Feed feed = new Feed("url", new Date(), "title"); + feed.setItems(new ArrayList<FeedItem>()); + + // create Feed image + File imgFile = new File(destFolder, "image"); + assertTrue(imgFile.createNewFile()); + FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true); + image.setOwner(feed); + feed.setImage(image); + + // create items with images + for (int i = 0; i < 10; i++) { + FeedItem item = new FeedItem(0, "Item " + i, "Item" + i, "url", new Date(), true, feed); + feed.getItems().add(item); + File itemImageFile = new File(destFolder, "item-image-" + i); + FeedImage itemImage = new FeedImage(0, "item-image" + i, itemImageFile.getAbsolutePath(), "url", true); + item.setImage(itemImage); + } + + PodDBAdapter adapter = new PodDBAdapter(getInstrumentation().getContext()); + adapter.open(); + adapter.setCompleteFeed(feed); + adapter.close(); + + assertTrue(feed.getId() != 0); + assertTrue(feed.getImage().getId() != 0); + for (FeedItem item : feed.getItems()) { + assertTrue(item.getId() != 0); + assertTrue(item.getImage().getId() != 0); + } + + DBWriter.deleteFeed(getInstrumentation().getTargetContext(), feed.getId()).get(TIMEOUT, TimeUnit.SECONDS); + + // check if files still exist + assertFalse(imgFile.exists()); + + adapter = new PodDBAdapter(getInstrumentation().getContext()); + adapter.open(); + Cursor c = adapter.getFeedCursor(feed.getId()); + assertTrue(c.getCount() == 0); + c.close(); + c = adapter.getImageCursor(image.getId()); + assertTrue(c.getCount() == 0); + c.close(); + for (FeedItem item : feed.getItems()) { + c = adapter.getFeedItemCursor(String.valueOf(item.getId())); + assertTrue(c.getCount() == 0); + c.close(); + c = adapter.getImageCursor(item.getImage().getId()); + assertEquals(0, c.getCount()); + c.close(); + } + } + public void testDeleteFeedWithQueueItems() throws ExecutionException, InterruptedException, TimeoutException { File destFolder = getInstrumentation().getTargetContext().getExternalFilesDir(TEST_FOLDER); assertNotNull(destFolder); @@ -305,7 +363,7 @@ public class DBWriterTest extends InstrumentationTestCase { // create Feed image File imgFile = new File(destFolder, "image"); FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true); - image.setFeed(feed); + image.setOwner(feed); feed.setImage(image); List<File> itemFiles = new ArrayList<File>(); @@ -350,7 +408,7 @@ public class DBWriterTest extends InstrumentationTestCase { Cursor c = adapter.getFeedCursor(feed.getId()); assertTrue(c.getCount() == 0); c.close(); - c = adapter.getImageOfFeedCursor(image.getId()); + c = adapter.getImageCursor(image.getId()); assertTrue(c.getCount() == 0); c.close(); for (FeedItem item : feed.getItems()) { @@ -377,7 +435,7 @@ public class DBWriterTest extends InstrumentationTestCase { // create Feed image File imgFile = new File(destFolder, "image"); FeedImage image = new FeedImage(0, "image", imgFile.getAbsolutePath(), "url", true); - image.setFeed(feed); + image.setOwner(feed); feed.setImage(image); List<File> itemFiles = new ArrayList<File>(); @@ -412,7 +470,7 @@ public class DBWriterTest extends InstrumentationTestCase { Cursor c = adapter.getFeedCursor(feed.getId()); assertTrue(c.getCount() == 0); c.close(); - c = adapter.getImageOfFeedCursor(image.getId()); + c = adapter.getImageCursor(image.getId()); assertTrue(c.getCount() == 0); c.close(); for (FeedItem item : feed.getItems()) { diff --git a/src/instrumentationTest/de/test/antennapod/util/URIUtilTest.java b/src/instrumentationTest/de/test/antennapod/util/URIUtilTest.java new file mode 100644 index 000000000..a7cba4c03 --- /dev/null +++ b/src/instrumentationTest/de/test/antennapod/util/URIUtilTest.java @@ -0,0 +1,21 @@ +package instrumentationTest.de.test.antennapod.util; + +import android.test.AndroidTestCase; +import de.danoeh.antennapod.util.URIUtil; + +/** + * Test class for URIUtil + */ +public class URIUtilTest extends AndroidTestCase { + + public void testGetURIFromRequestUrlShouldNotEncode() { + final String testUrl = "http://example.com/this%20is%20encoded"; + assertEquals(testUrl, URIUtil.getURIFromRequestUrl(testUrl).toString()); + } + + public void testGetURIFromRequestUrlShouldEncode() { + final String testUrl = "http://example.com/this is not encoded"; + final String expected = "http://example.com/this%20is%20not%20encoded"; + assertEquals(expected, URIUtil.getURIFromRequestUrl(testUrl).toString()); + } +} |