From d86a2a1977b8a27368956546d892e09c71a8963e Mon Sep 17 00:00:00 2001 From: Michael Scarito Date: Thu, 20 Nov 2014 14:14:10 -0800 Subject: [PATCH 01/36] Resume on headphone connect if paused by headphone disconnect --- .../service/playback/PlaybackService.java | 19 +++++++++++++++++++ .../playback/PlaybackServiceMediaPlayer.java | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index a5560e3fb..0ff057a26 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -144,6 +144,10 @@ public class PlaybackService extends Service { * Is true if service has received a valid start command. */ public static boolean started = false; + /** + * Is true if the service was running, but paused due to headphone disconnect + */ + public static boolean headphonePause = false; private static final int NOTIFICATION_ID = 1; @@ -966,6 +970,7 @@ public class PlaybackService extends Service { private BroadcastReceiver headsetDisconnected = new BroadcastReceiver() { private static final String TAG = "headsetDisconnected"; private static final int UNPLUGGED = 0; + private static final int PLUGGED = 1; @Override public void onReceive(Context context, Intent intent) { @@ -978,6 +983,10 @@ public class PlaybackService extends Service { if (BuildConfig.DEBUG) Log.d(TAG, "Headset was unplugged during playback."); pauseIfPauseOnDisconnect(); + } else if (state == PLUGGED) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Headset was plugged in during playback."); + unpauseIfPauseOnDisconnect(); } } else { Log.e(TAG, "Received invalid ACTION_HEADSET_PLUG intent"); @@ -1003,6 +1012,9 @@ public class PlaybackService extends Service { */ private void pauseIfPauseOnDisconnect() { if (UserPreferences.isPauseOnHeadsetDisconnect()) { + if (mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING) { + headphonePause = true; + } if (UserPreferences.isPersistNotify()) { mediaPlayer.pause(false, true); } else { @@ -1011,6 +1023,13 @@ public class PlaybackService extends Service { } } + private void unpauseIfPauseOnDisconnect() { + if (UserPreferences.isPauseOnHeadsetDisconnect() && headphonePause) { + headphonePause = false; + mediaPlayer.resume(); + } + } + private BroadcastReceiver shutdownReceiver = new BroadcastReceiver() { @Override diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java index dbf870eac..ad5154faf 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackServiceMediaPlayer.java @@ -586,6 +586,10 @@ public class PlaybackServiceMediaPlayer { return mediaType; } + public PlayerStatus getPlayerStatus() { + return playerStatus; + } + public boolean isStreaming() { return stream; } From d15acebd8b688132c8d13f6285e35e9b4b4afcb7 Mon Sep 17 00:00:00 2001 From: Michael Scarito Date: Thu, 20 Nov 2014 14:14:19 -0800 Subject: [PATCH 02/36] Renamed headphonePause to transientPause --- .../antennapod/core/service/playback/PlaybackService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index 0ff057a26..a2646b981 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -147,7 +147,7 @@ public class PlaybackService extends Service { /** * Is true if the service was running, but paused due to headphone disconnect */ - public static boolean headphonePause = false; + public static boolean transientPause = false; private static final int NOTIFICATION_ID = 1; @@ -1013,7 +1013,7 @@ public class PlaybackService extends Service { private void pauseIfPauseOnDisconnect() { if (UserPreferences.isPauseOnHeadsetDisconnect()) { if (mediaPlayer.getPlayerStatus() == PlayerStatus.PLAYING) { - headphonePause = true; + transientPause = true; } if (UserPreferences.isPersistNotify()) { mediaPlayer.pause(false, true); @@ -1024,8 +1024,8 @@ public class PlaybackService extends Service { } private void unpauseIfPauseOnDisconnect() { - if (UserPreferences.isPauseOnHeadsetDisconnect() && headphonePause) { - headphonePause = false; + if (UserPreferences.isPauseOnHeadsetDisconnect() && transientPause) { + transientPause = false; mediaPlayer.resume(); } } From d4a3095512a2b1eaf5517699e63f38b4d73546de Mon Sep 17 00:00:00 2001 From: Michael Scarito Date: Thu, 20 Nov 2014 14:14:25 -0800 Subject: [PATCH 03/36] Added bluetooth BroadcastReceiver to resume after disconnect --- .../core/service/playback/PlaybackService.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index a2646b981..b6e87f5ae 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -210,6 +210,8 @@ public class PlaybackService extends Service { Intent.ACTION_HEADSET_PLUG)); registerReceiver(shutdownReceiver, new IntentFilter( ACTION_SHUTDOWN_PLAYBACK_SERVICE)); + registerReceiver(bluetoothStateUpdated, new IntentFilter( + AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)); registerReceiver(audioBecomingNoisy, new IntentFilter( AudioManager.ACTION_AUDIO_BECOMING_NOISY)); registerReceiver(skipCurrentEpisodeReceiver, new IntentFilter( @@ -232,6 +234,7 @@ public class PlaybackService extends Service { unregisterReceiver(headsetDisconnected); unregisterReceiver(shutdownReceiver); + unregisterReceiver(bluetoothStateUpdated); unregisterReceiver(audioBecomingNoisy); unregisterReceiver(skipCurrentEpisodeReceiver); mediaPlayer.shutdown(); @@ -995,6 +998,21 @@ public class PlaybackService extends Service { } }; + private BroadcastReceiver bluetoothStateUpdated = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (StringUtils.equals(intent.getAction(), AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) { + int state = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1); + int prevState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, -1); + if (state == AudioManager.SCO_AUDIO_STATE_CONNECTED) { + if (BuildConfig.DEBUG) + Log.d(TAG, "Received bluetooth connection intent"); + unpauseIfPauseOnDisconnect(); + } + } + } + }; + private BroadcastReceiver audioBecomingNoisy = new BroadcastReceiver() { @Override From 58f071e763ac6793f8494cb09d1382898116ed1a Mon Sep 17 00:00:00 2001 From: Michael Scarito Date: Fri, 21 Nov 2014 10:24:29 -0800 Subject: [PATCH 04/36] Created a user preference to enable the headphone resume feature --- .../java/de/test/antennapod/ui/PlaybackTest.java | 1 + app/src/main/res/xml/preferences.xml | 7 +++++++ .../antennapod/core/preferences/UserPreferences.java | 11 +++++++++++ .../core/service/playback/PlaybackService.java | 6 ++++-- core/src/main/res/values/strings.xml | 2 ++ 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java index daae4bd62..2235ee6f4 100644 --- a/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java +++ b/app/src/androidTest/java/de/test/antennapod/ui/PlaybackTest.java @@ -41,6 +41,7 @@ public class PlaybackTest extends ActivityInstrumentationTestCase2 adapter.open(); adapter.close(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getInstrumentation().getTargetContext()); + prefs.edit().putBoolean(UserPreferences.PREF_UNPAUSE_ON_HEADSET_RECONNECT, false).commit(); prefs.edit().putBoolean(UserPreferences.PREF_PAUSE_ON_HEADSET_DISCONNECT, false).commit(); } diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 5175acdcb..5f4a7583d 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -29,6 +29,13 @@ android:key="prefPauseOnHeadsetDisconnect" android:summary="@string/pref_pauseOnHeadsetDisconnect_sum" android:title="@string/pref_pauseOnHeadsetDisconnect_title"/> + Services Flattr Pause playback when the headphones are disconnected + Resume playback when the headphones are reconnected Jump to next queue item when playback completes Playback Network @@ -214,6 +215,7 @@ Continuous playback WiFi media download Headphones disconnect + Headphones reconnect Mobile updates Allow updates over the mobile data connection Refreshing From 30ac9ecf1d49097a7c308ef868eaaa796c52e034 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Wed, 10 Dec 2014 21:28:56 +0100 Subject: [PATCH 05/36] Upgraded dependencies Flattr4j has been upgraded to 2.12. This version makes it possible to use flattr on Android 2.3 devices. --- app/build.gradle | 4 +--- build.gradle | 2 +- core/build.gradle | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 14897139b..2294f8148 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -7,9 +7,7 @@ dependencies { compile 'com.android.support:support-v4:21.0.2' compile 'com.android.support:appcompat-v7:21.0.2' compile 'org.apache.commons:commons-lang3:3.3.2' - compile('org.shredzone.flattr4j:flattr4j-core:2.11') { - exclude group: 'org.apache.httpcomponents', module: 'httpcore' - exclude group: 'org.apache.httpcomponents', module: 'httpclient' + compile('org.shredzone.flattr4j:flattr4j-core:2.12') { exclude group: 'org.json', module: 'json' } compile 'commons-io:commons-io:2.4' diff --git a/build.gradle b/build.gradle index efa6e1773..9f1a2d6ab 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.0.0-rc4' + classpath 'com.android.tools.build:gradle:1.0.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/core/build.gradle b/core/build.gradle index cfe33c98c..3685d3403 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -34,9 +34,7 @@ dependencies { compile 'com.android.support:appcompat-v7:21.0.2' compile 'com.android.support:support-v4:21.0.2' compile 'org.apache.commons:commons-lang3:3.3.2' - compile ('org.shredzone.flattr4j:flattr4j-core:2.11') { - exclude group: 'org.apache.httpcomponents', module: 'httpcore' - exclude group: 'org.apache.httpcomponents', module: 'httpclient' + compile ('org.shredzone.flattr4j:flattr4j-core:2.12') { exclude group: 'org.json', module: 'json' } compile 'commons-io:commons-io:2.4' From e9ed796fd432f8bcd9b41f52c2777b00cadcbed8 Mon Sep 17 00:00:00 2001 From: Lee Yeong Khang Date: Thu, 11 Dec 2014 19:54:58 +0900 Subject: [PATCH 06/36] Combine play and pause button into 1 detailed in https://github.com/danieloeh/AntennaPod/issues/574 --- .../service/playback/PlaybackService.java | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java index a5560e3fb..7df4af504 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java +++ b/core/src/main/java/de/danoeh/antennapod/core/service/playback/PlaybackService.java @@ -284,18 +284,13 @@ public class PlaybackService extends Service { private void handleKeycode(int keycode) { if (BuildConfig.DEBUG) Log.d(TAG, "Handling keycode: " + keycode); - final PlaybackServiceMediaPlayer.PSMPInfo info = mediaPlayer.getPSMPInfo(); final PlayerStatus status = info.playerStatus; switch (keycode) { case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: if (status == PlayerStatus.PLAYING) { - if (UserPreferences.isPersistNotify()) { - mediaPlayer.pause(false, true); - } else { - mediaPlayer.pause(true, true); - } + mediaPlayer.pause(false, true); } else if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) { mediaPlayer.resume(); } else if (status == PlayerStatus.PREPARING) { @@ -315,11 +310,7 @@ public class PlaybackService extends Service { break; case KeyEvent.KEYCODE_MEDIA_PAUSE: if (status == PlayerStatus.PLAYING) { - if (UserPreferences.isPersistNotify()) { - mediaPlayer.pause(false, true); - } else { - mediaPlayer.pause(true, true); - } + mediaPlayer.pause(false, true); } break; case KeyEvent.KEYCODE_MEDIA_NEXT: @@ -333,7 +324,9 @@ public class PlaybackService extends Service { case KeyEvent.KEYCODE_MEDIA_STOP: if (status == PlayerStatus.PLAYING) { mediaPlayer.pause(true, true); + started = false; } + stopForeground(true); // gets rid of persistent notification break; default: @@ -409,12 +402,8 @@ public class PlaybackService extends Service { taskManager.cancelPositionSaver(); saveCurrentPosition(false, 0); taskManager.cancelWidgetUpdater(); - if (UserPreferences.isPersistNotify() && android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - // do not remove notification on pause based on user pref and whether android version supports expanded notifications - } else { - // remove notifcation on pause - stopForeground(true); - } + setupNotification(newInfo); + break; case STOPPED: @@ -431,6 +420,7 @@ public class PlaybackService extends Service { taskManager.startPositionSaver(); taskManager.startWidgetUpdater(); setupNotification(newInfo); + started = true; break; case ERROR: writePlaybackPreferencesNoMediaPlaying(); @@ -734,8 +724,9 @@ public class PlaybackService extends Service { PlaybackServiceMediaPlayer.PSMPInfo newInfo = mediaPlayer.getPSMPInfo(); final int smallIcon = ClientConfig.playbackServiceCallbacks.getNotificationIconResource(getApplicationContext()); - if (!isCancelled() && info.playerStatus == PlayerStatus.PLAYING - && info.playable != null) { + if (!isCancelled() && + started == true && + info.playable != null) { String contentText = info.playable.getFeedTitle(); String contentTitle = info.playable.getEpisodeTitle(); Notification notification = null; @@ -775,14 +766,17 @@ public class PlaybackService extends Service { .setContentIntent(pIntent) .setLargeIcon(icon) .setSmallIcon(smallIcon) - .setPriority(UserPreferences.getNotifyPriority()) // set notification priority - .addAction(android.R.drawable.ic_media_play, //play action - getString(R.string.play_label), - playButtonPendingIntent) - .addAction(android.R.drawable.ic_media_pause, //pause action - getString(R.string.pause_label), - pauseButtonPendingIntent) - .addAction(android.R.drawable.ic_menu_close_clear_cancel, // stop action + .setPriority(UserPreferences.getNotifyPriority()); // set notification priority + if(newInfo.playerStatus==PlayerStatus.PLAYING){ + notificationBuilder.addAction(android.R.drawable.ic_media_pause, //pause action + getString(R.string.pause_label), + pauseButtonPendingIntent); + } else { + notificationBuilder.addAction(android.R.drawable.ic_media_play, //play action + getString(R.string.play_label), + playButtonPendingIntent); + } + notificationBuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, // stop action getString(R.string.stop_label), stopButtonPendingIntent); notification = notificationBuilder.build(); @@ -795,9 +789,7 @@ public class PlaybackService extends Service { .setSmallIcon(smallIcon); notification = notificationBuilder.getNotification(); } - if (newInfo.playerStatus == PlayerStatus.PLAYING) { - startForeground(NOTIFICATION_ID, notification); - } + startForeground(NOTIFICATION_ID, notification); if (BuildConfig.DEBUG) Log.d(TAG, "Notification set up"); } From 8083a064a0d94c90c1927932f2cb01bac69af6ad Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 4 Dec 2014 12:16:47 +0100 Subject: [PATCH 07/36] Improved look of ItemlistFragment header --- .../antennapod/fragment/ItemlistFragment.java | 9 + .../main/res/layout/feeditemlist_header.xml | 17 +- .../core/asynctask/PicassoProvider.java | 250 ++++++++++++++++++ core/src/main/res/values/colors.xml | 1 + core/src/main/res/values/styles.xml | 6 + 5 files changed, 280 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java index be9a9c12d..51dfcf153 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemlistFragment.java @@ -35,6 +35,7 @@ import de.danoeh.antennapod.adapter.DefaultActionButtonCallback; import de.danoeh.antennapod.adapter.FeedItemlistAdapter; import de.danoeh.antennapod.core.asynctask.DownloadObserver; import de.danoeh.antennapod.core.asynctask.FeedRemover; +import de.danoeh.antennapod.core.asynctask.PicassoProvider; import de.danoeh.antennapod.core.dialog.ConfirmationDialog; import de.danoeh.antennapod.core.dialog.DownloadRequestErrorDialogCreator; import de.danoeh.antennapod.core.feed.EventDistributor; @@ -362,12 +363,20 @@ public class ItemlistFragment extends ListFragment { TextView txtvTitle = (TextView) header.findViewById(R.id.txtvTitle); TextView txtvAuthor = (TextView) header.findViewById(R.id.txtvAuthor); + ImageView imgvBackground = (ImageView) header.findViewById(R.id.imgvBackground); ImageView imgvCover = (ImageView) header.findViewById(R.id.imgvCover); ImageButton butShowInfo = (ImageButton) header.findViewById(R.id.butShowInfo); txtvTitle.setText(feed.getTitle()); txtvAuthor.setText(feed.getAuthor()); + Picasso.with(getActivity()) + .load(feed.getImageUri()) + .placeholder(R.color.image_readability_tint) + .error(R.color.image_readability_tint) + .transform(PicassoProvider.blurTransformation) + .into(imgvBackground); + Picasso.with(getActivity()) .load(feed.getImageUri()) .fit() diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml index fc38c6797..e55ef4c3e 100644 --- a/app/src/main/res/layout/feeditemlist_header.xml +++ b/app/src/main/res/layout/feeditemlist_header.xml @@ -6,6 +6,12 @@ android:layout_height="@dimen/feeditemlist_header_height" tools:context="de.danoeh.antennapod.activity.MainActivity"> + + + android:src="@drawable/ic_info_white_24dp" /> + android:maxLines="2" + android:shadowColor="@color/black" + android:shadowRadius="3" + android:textColor="@color/white" /> diff --git a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java index 1ed29c23a..0b136afe7 100644 --- a/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java +++ b/core/src/main/java/de/danoeh/antennapod/core/asynctask/PicassoProvider.java @@ -14,6 +14,7 @@ import com.squareup.picasso.OkHttpDownloader; import com.squareup.picasso.Picasso; import com.squareup.picasso.Request; import com.squareup.picasso.RequestHandler; +import com.squareup.picasso.Transformation; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; @@ -209,4 +210,253 @@ public class PicassoProvider { options.inJustDecodeBounds = false; } } + + public static final int BLUR_RADIUS = 10; + public static final String BLUR_KEY = "blur"; + + public static final Transformation blurTransformation = new Transformation() { + @Override + public Bitmap transform(Bitmap source) { + Bitmap result = fastblur(source, BLUR_RADIUS); + source.recycle(); + return result; + } + + @Override + public String key() { + return BLUR_KEY; + } + }; + + public static Bitmap fastblur(Bitmap sentBitmap, int radius) { + + // Stack Blur v1.0 from + // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html + // + // Java Author: Mario Klingemann + // http://incubator.quasimondo.com + // created Feburary 29, 2004 + // Android port : Yahel Bouaziz + // http://www.kayenko.com + // ported april 5th, 2012 + + // This is a compromise between Gaussian Blur and Box blur + // It creates much better looking blurs than Box Blur, but is + // 7x faster than my Gaussian Blur implementation. + // + // I called it Stack Blur because this describes best how this + // filter works internally: it creates a kind of moving stack + // of colors whilst scanning through the image. Thereby it + // just has to add one new block of color to the right side + // of the stack and remove the leftmost color. The remaining + // colors on the topmost layer of the stack are either added on + // or reduced by one, depending on if they are on the right or + // on the left side of the stack. + // + // If you are using this algorithm in your code please add + // the following line: + // + // Stack Blur Algorithm by Mario Klingemann + + Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); + + if (radius < 1) { + return (null); + } + + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + int[] pix = new int[w * h]; + Log.e("pix", w + " " + h + " " + pix.length); + bitmap.getPixels(pix, 0, w, 0, 0, w, h); + + int wm = w - 1; + int hm = h - 1; + int wh = w * h; + int div = radius + radius + 1; + + int r[] = new int[wh]; + int g[] = new int[wh]; + int b[] = new int[wh]; + int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; + int vmin[] = new int[Math.max(w, h)]; + + int divsum = (div + 1) >> 1; + divsum *= divsum; + int dv[] = new int[256 * divsum]; + for (i = 0; i < 256 * divsum; i++) { + dv[i] = (i / divsum); + } + + yw = yi = 0; + + int[][] stack = new int[div][3]; + int stackpointer; + int stackstart; + int[] sir; + int rbs; + int r1 = radius + 1; + int routsum, goutsum, boutsum; + int rinsum, ginsum, binsum; + + for (y = 0; y < h; y++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + for (i = -radius; i <= radius; i++) { + p = pix[yi + Math.min(wm, Math.max(i, 0))]; + sir = stack[i + radius]; + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + rbs = r1 - Math.abs(i); + rsum += sir[0] * rbs; + gsum += sir[1] * rbs; + bsum += sir[2] * rbs; + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + } + stackpointer = radius; + + for (x = 0; x < w; x++) { + + r[yi] = dv[rsum]; + g[yi] = dv[gsum]; + b[yi] = dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (y == 0) { + vmin[x] = Math.min(x + radius + 1, wm); + } + p = pix[yw + vmin[x]]; + + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[(stackpointer) % div]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi++; + } + yw += w; + } + for (x = 0; x < w; x++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + yp = -radius * w; + for (i = -radius; i <= radius; i++) { + yi = Math.max(0, yp) + x; + + sir = stack[i + radius]; + + sir[0] = r[yi]; + sir[1] = g[yi]; + sir[2] = b[yi]; + + rbs = r1 - Math.abs(i); + + rsum += r[yi] * rbs; + gsum += g[yi] * rbs; + bsum += b[yi] * rbs; + + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + + if (i < hm) { + yp += w; + } + } + yi = x; + stackpointer = radius; + for (y = 0; y < h; y++) { + // Preserve alpha channel: ( 0xff000000 & pix[yi] ) + pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (x == 0) { + vmin[y] = Math.min(y + r1, hm) * w; + } + p = x + vmin[y]; + + sir[0] = r[p]; + sir[1] = g[p]; + sir[2] = b[p]; + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[stackpointer]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi += w; + } + } + + Log.e("pix", w + " " + h + " " + pix.length); + bitmap.setPixels(pix, 0, w, 0, 0, w, h); + + return (bitmap); + } } diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml index ab48fafe7..f062f23ea 100644 --- a/core/src/main/res/values/colors.xml +++ b/core/src/main/res/values/colors.xml @@ -16,6 +16,7 @@ #EDEDED #060708 #669900 + #80000000 #FEBB20 diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml index df7ae385c..d9f6a775a 100644 --- a/core/src/main/res/values/styles.xml +++ b/core/src/main/res/values/styles.xml @@ -157,4 +157,10 @@ @string/new_label + + From 6962d139746347aff034e3a84eaecf3e98062160 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Thu, 4 Dec 2014 16:34:32 +0100 Subject: [PATCH 08/36] Updated audio player layout --- .../activity/AudioplayerActivity.java | 180 +++++------ .../activity/MediaplayerActivity.java | 1 - .../activity/VideoplayerActivity.java | 1 + .../adapter/ChapterListAdapter.java | 21 +- .../antennapod/fragment/CoverFragment.java | 11 + .../fragment/ItemDescriptionFragment.java | 1 - .../res/layout-land/audioplayer_activity.xml | 188 ------------ .../main/res/layout/audioplayer_activity.xml | 285 ++++++++---------- app/src/main/res/layout/cover_fragment.xml | 4 +- .../main/res/layout/simplechapter_item.xml | 78 +++-- app/src/main/res/menu/mediaplayer.xml | 2 +- .../core/preferences/UserPreferences.java | 9 + .../core/util/playback/Timeline.java | 2 +- core/src/main/res/values/colors.xml | 4 +- core/src/main/res/values/dimens.xml | 2 + core/src/main/res/values/styles.xml | 83 +++++ 16 files changed, 406 insertions(+), 466 deletions(-) delete mode 100644 app/src/main/res/layout-land/audioplayer_activity.xml diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java index eb7a844db..f124de947 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/AudioplayerActivity.java @@ -11,6 +11,7 @@ import android.support.v4.app.FragmentTransaction; import android.support.v4.app.ListFragment; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; +import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -21,9 +22,7 @@ import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ImageButton; -import android.widget.ImageView.ScaleType; import android.widget.ListView; -import android.widget.TextView; import com.squareup.picasso.Picasso; @@ -59,6 +58,7 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc private static final int POS_DESCR = 1; private static final int POS_CHAPTERS = 2; private static final int NUM_CONTENT_FRAGMENTS = 3; + private static final int POS_NONE = -1; final String TAG = "AudioplayerActivity"; private static final String PREFS = "AudioPlayerActivityPreferences"; @@ -78,15 +78,15 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc private Fragment currentlyShownFragment; private int currentlyShownPosition = -1; + private int lastShownPosition = POS_NONE; /** * Used if onResume was called without loadMediaInfo. */ private int savedPosition = -1; - private TextView txtvTitle; private Button butPlaybackSpeed; - private ImageButton butNavLeft; - private ImageButton butNavRight; + private ImageButton butNavChaptersShownotes; + private ImageButton butShowCover; private void resetFragmentView() { FragmentTransaction fT = getSupportFragmentManager().beginTransaction(); @@ -138,10 +138,14 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc } + @Override + protected void chooseTheme() { + setTheme(UserPreferences.getNoTitleTheme()); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - getSupportActionBar().setDisplayShowTitleEnabled(false); detachedFragments = new Fragment[NUM_CONTENT_FRAGMENTS]; } @@ -320,24 +324,32 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc chapterFragment = new ListFragment() { @Override - public void onListItemClick(ListView l, View v, - int position, long id) { - super.onListItemClick(l, v, position, id); - Chapter chapter = (Chapter) this - .getListAdapter().getItem(position); - controller.seekToChapter(chapter); + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + // add padding + final ListView lv = getListView(); + lv.setClipToPadding(false); + final int vertPadding = getResources().getDimensionPixelSize(R.dimen.list_vertical_padding); + lv.setPadding(0, vertPadding, 0, vertPadding); } - }; chapterFragment.setListAdapter(new ChapterListAdapter( AudioplayerActivity.this, 0, media - .getChapters(), media + .getChapters(), media, new ChapterListAdapter.Callback() { + @Override + public void onPlayChapterButtonClicked(int position) { + Chapter chapter = (Chapter) + chapterFragment.getListAdapter().getItem(position); + controller.seekToChapter(chapter); + } + } )); } currentlyShownFragment = chapterFragment; break; } if (currentlyShownFragment != null) { + lastShownPosition = currentlyShownPosition; currentlyShownPosition = pos; if (detachedFragments[pos] != null) { if (BuildConfig.DEBUG) @@ -355,78 +367,68 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc } } + /** + * Switches to the fragment that was displayed before the current one or the description fragment + * if no fragment was previously displayed. + */ + public void switchToLastFragment() { + if (lastShownPosition != POS_NONE) { + switchToFragment(lastShownPosition); + } else { + switchToFragment(POS_DESCR); + } + } + private void updateNavButtonDrawable() { final int[] buttonTexts = new int[]{R.string.show_shownotes_label, - R.string.show_chapters_label, R.string.show_cover_label}; + R.string.show_chapters_label}; final TypedArray drawables = obtainStyledAttributes(new int[]{ 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); + if (butNavChaptersShownotes != null && butShowCover != null && media != null) { + butNavChaptersShownotes.setTag(R.id.imageloader_key, null); + setNavButtonVisibility(); switch (currentlyShownPosition) { case POS_COVER: - butNavLeft.setScaleType(ScaleType.CENTER); - butNavLeft.setImageDrawable(drawables.getDrawable(0)); - butNavLeft.setContentDescription(getString(buttonTexts[0])); - - butNavRight.setImageDrawable(drawables.getDrawable(1)); - butNavRight.setContentDescription(getString(buttonTexts[1])); - + butShowCover.setVisibility(View.GONE); + if (lastShownPosition == POS_CHAPTERS) { + butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1)); + butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1])); + } else { + butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0)); + butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0])); + } break; case POS_DESCR: - butNavLeft.setScaleType(ScaleType.CENTER_CROP); - butNavLeft.post(new Runnable() { - - @Override - public void run() { - Picasso.with(AudioplayerActivity.this) - .load(media.getImageUri()) - .fit() - .into(butNavLeft); - } - }); - butNavLeft.setContentDescription(getString(buttonTexts[2])); - - butNavRight.setImageDrawable(drawables.getDrawable(1)); - butNavRight.setContentDescription(getString(buttonTexts[1])); + butShowCover.setVisibility(View.VISIBLE); + butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(1)); + butNavChaptersShownotes.setContentDescription(getString(buttonTexts[1])); break; case POS_CHAPTERS: - butNavLeft.setScaleType(ScaleType.CENTER_CROP); - butNavLeft.post(new Runnable() { - - @Override - public void run() { - Picasso.with(AudioplayerActivity.this) - .load(media.getImageUri()) - .fit() - .into(butNavLeft); - } - - }); - butNavLeft.setContentDescription(getString(buttonTexts[2])); - - butNavRight.setImageDrawable(drawables.getDrawable(0)); - butNavRight.setContentDescription(getString(buttonTexts[0])); + butShowCover.setVisibility(View.VISIBLE); + butNavChaptersShownotes.setImageDrawable(drawables.getDrawable(0)); + butNavChaptersShownotes.setContentDescription(getString(buttonTexts[0])); break; } } + drawables.recycle(); } @Override protected void setupGUI() { super.setupGUI(); resetFragmentView(); + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); navList = (ListView) findViewById(R.id.nav_list); - txtvTitle = (TextView) findViewById(R.id.txtvTitle); - butNavLeft = (ImageButton) findViewById(R.id.butNavLeft); - butNavRight = (ImageButton) findViewById(R.id.butNavRight); butPlaybackSpeed = (Button) findViewById(R.id.butPlaybackSpeed); + butNavChaptersShownotes = (ImageButton) findViewById(R.id.butNavChaptersShownotes); + butShowCover = (ImageButton) findViewById(R.id.butCover); drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, R.string.drawer_close) { CharSequence currentTitle = getSupportActionBar().getTitle(); @@ -468,33 +470,26 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc }); drawerToggle.syncState(); - butNavLeft.setOnClickListener(new OnClickListener() { - - @Override - public void onClick(View v) { - if (currentlyShownFragment == null - || currentlyShownPosition == POS_DESCR) { - switchToFragment(POS_COVER); - } else if (currentlyShownPosition == POS_COVER) { - switchToFragment(POS_DESCR); - } else if (currentlyShownPosition == POS_CHAPTERS) { - switchToFragment(POS_COVER); - } - } - }); - - butNavRight.setOnClickListener(new OnClickListener() { - + butNavChaptersShownotes.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (currentlyShownPosition == POS_CHAPTERS) { switchToFragment(POS_DESCR); - } else { + } else if (currentlyShownPosition == POS_DESCR) { switchToFragment(POS_CHAPTERS); + } else if (currentlyShownPosition == POS_COVER) { + switchToLastFragment(); } } }); + butShowCover.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + switchToFragment(POS_COVER); + } + }); + butPlaybackSpeed.setOnClickListener(new OnClickListener() { @Override @@ -539,6 +534,22 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc }); } + private void setNavButtonVisibility() { + if (butNavChaptersShownotes != null) { + if (controller != null) { + Playable media = controller.getMedia(); + if (media != null) { + if (media.getChapters() != null || currentlyShownPosition == POS_COVER) { + butNavChaptersShownotes.setVisibility(View.VISIBLE); + return; + } + } + } + butNavChaptersShownotes.setVisibility(View.GONE); + } + + } + @Override protected void onPlaybackSpeedChange() { super.onPlaybackSpeedChange(); @@ -566,13 +577,14 @@ public class AudioplayerActivity extends MediaplayerActivity implements ItemDesc if (media == null) { return false; } - txtvTitle.setText(media.getEpisodeTitle()); - if (media.getChapters() != null) { - butNavRight.setVisibility(View.VISIBLE); - } else { - butNavRight.setVisibility(View.INVISIBLE); - } + getSupportActionBar().setTitle(media.getEpisodeTitle()); + Picasso.with(this) + .load(media.getImageUri()) + .fit() + .into(butShowCover); + + setNavButtonVisibility(); if (currentlyShownPosition == -1) { if (!restoreFromPreferences()) { diff --git a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java index 561188291..099e96be9 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/MediaplayerActivity.java @@ -174,7 +174,6 @@ public abstract class MediaplayerActivity extends ActionBarActivity orientation = getResources().getConfiguration().orientation; getWindow().setFormat(PixelFormat.TRANSPARENT); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @Override diff --git a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java index 727b25296..60eb290b5 100644 --- a/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java +++ b/app/src/main/java/de/danoeh/antennapod/activity/VideoplayerActivity.java @@ -111,6 +111,7 @@ public class VideoplayerActivity extends MediaplayerActivity { @Override protected void setupGUI() { super.setupGUI(); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); videoOverlay = (LinearLayout) findViewById(R.id.overlay); videoview = (AspectRatioVideoView) findViewById(R.id.videoview); progressIndicator = (ProgressBar) findViewById(R.id.progressIndicator); diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java index 9e59a2a1a..67fb4c3b1 100644 --- a/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java +++ b/app/src/main/java/de/danoeh/antennapod/adapter/ChapterListAdapter.java @@ -14,6 +14,7 @@ import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import android.widget.ImageButton; import android.widget.TextView; import de.danoeh.antennapod.R; import de.danoeh.antennapod.core.feed.Chapter; @@ -31,16 +32,18 @@ public class ChapterListAdapter extends ArrayAdapter { private Playable media; private int defaultTextColor; + private final Callback callback; public ChapterListAdapter(Context context, int textViewResourceId, - List objects, Playable media) { + List objects, Playable media, Callback callback) { super(context, textViewResourceId, objects); this.chapters = objects; this.media = media; + this.callback = callback; } @Override - public View getView(int position, View convertView, ViewGroup parent) { + public View getView(final int position, View convertView, ViewGroup parent) { Holder holder; Chapter sc = getItem(position); @@ -56,6 +59,7 @@ public class ChapterListAdapter extends ArrayAdapter { defaultTextColor = holder.title.getTextColors().getDefaultColor(); holder.start = (TextView) convertView.findViewById(R.id.txtvStart); holder.link = (TextView) convertView.findViewById(R.id.txtvLink); + holder.butPlayChapter = (ImageButton) convertView.findViewById(R.id.butPlayChapter); convertView.setTag(holder); } else { holder = (Holder) convertView.getTag(); @@ -122,6 +126,14 @@ public class ChapterListAdapter extends ArrayAdapter { } }); + holder.butPlayChapter.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (callback != null) { + callback.onPlayChapterButtonClicked(position); + } + } + }); Chapter current = ChapterUtils.getCurrentChapter(media); if (current != null) { if (current == sc) { @@ -144,6 +156,7 @@ public class ChapterListAdapter extends ArrayAdapter { TextView title; TextView start; TextView link; + ImageButton butPlayChapter; } @Override @@ -177,4 +190,8 @@ public class ChapterListAdapter extends ArrayAdapter { return super.getItem(position); } + public static interface Callback { + public void onPlayChapterButtonClicked(int position); + } + } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java index efe3e7ab4..3076f8136 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/CoverFragment.java @@ -1,5 +1,6 @@ package de.danoeh.antennapod.fragment; +import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.support.v4.app.Fragment; @@ -13,6 +14,7 @@ import com.squareup.picasso.Picasso; import de.danoeh.antennapod.BuildConfig; import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.AudioplayerActivity; import de.danoeh.antennapod.activity.AudioplayerActivity.AudioplayerContentFragment; import de.danoeh.antennapod.core.util.playback.Playable; @@ -57,6 +59,15 @@ public class CoverFragment extends Fragment implements Bundle savedInstanceState) { View root = inflater.inflate(R.layout.cover_fragment, container, false); imgvCover = (ImageView) root.findViewById(R.id.imgvCover); + imgvCover.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Activity activity = getActivity(); + if (activity != null && activity instanceof AudioplayerActivity) { + ((AudioplayerActivity)activity).switchToLastFragment(); + } + } + }); viewCreated = true; return root; } diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java index c0222de8e..a7c6d62e6 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java @@ -12,7 +12,6 @@ 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.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; diff --git a/app/src/main/res/layout-land/audioplayer_activity.xml b/app/src/main/res/layout-land/audioplayer_activity.xml deleted file mode 100644 index 1f78902c9..000000000 --- a/app/src/main/res/layout-land/audioplayer_activity.xml +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -