From b07e602651168d165d1318bdd18d0407a732bb61 Mon Sep 17 00:00:00 2001 From: Karim Abou Zeid Date: Thu, 11 Jun 2015 16:28:04 +0200 Subject: [PATCH] Fixed an annoying bug in the MusicControllerActivity where the recents card of the app is placed at the wrong position when switching between the songs. Also some code clean ups. --- app/build.gradle | 4 +- .../prefs/ColorChooserPreference.java | 2 +- .../activities/MusicControllerActivity.java | 59 ++++---- .../ui/activities/base/ThemeBaseActivity.java | 15 +- .../com/kabouzeid/gramophone/util/Util.java | 5 +- .../gramophone/views/DynamicSwitch.java | 131 ++++++++++++++++++ ...ustom.xml => preference_color_chooser.xml} | 0 app/src/main/res/menu/menu_music_playing.xml | 8 +- app/src/main/res/xml/pref_audio.xml | 3 +- app/src/main/res/xml/pref_colors.xml | 5 +- app/src/main/res/xml/pref_general.xml | 1 - .../main/res/xml/pref_now_playing_screen.xml | 6 - 12 files changed, 182 insertions(+), 57 deletions(-) create mode 100644 app/src/main/java/com/kabouzeid/gramophone/views/DynamicSwitch.java rename app/src/main/res/layout/{preference_custom.xml => preference_color_chooser.xml} (100%) diff --git a/app/build.gradle b/app/build.gradle index 2d605ee0..093d2720 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -27,8 +27,8 @@ android { applicationId "com.kabouzeid.gramophone" minSdkVersion 16 targetSdkVersion 22 - versionCode 32 - versionName "0.9.17b dev-1" + versionCode 33 + versionName "0.9.18b dev-1" } buildTypes { diff --git a/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java b/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java index 9748b77d..f1bf6ca4 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java +++ b/app/src/main/java/com/kabouzeid/gramophone/prefs/ColorChooserPreference.java @@ -25,7 +25,7 @@ public class ColorChooserPreference extends Preference { public ColorChooserPreference(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); - setLayoutResource(R.layout.preference_custom); + setLayoutResource(R.layout.preference_color_chooser); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java index 8cd6186b..f2012305 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MusicControllerActivity.java @@ -78,7 +78,7 @@ public class MusicControllerActivity extends AbsFabActivity { private Toolbar toolbar; private int lastFooterColor = -1; private int lastTextColor = -2; - private boolean killThreads = false; + private Thread progressViewsUpdateThread; private final boolean opaqueStatusBar = PreferenceUtils.getInstance(this).opaqueStatusbarNowPlaying(); private final boolean opaqueToolBar = opaqueStatusBar && PreferenceUtils.getInstance(this).opaqueToolbarNowPlaying(); @@ -169,7 +169,7 @@ public class MusicControllerActivity extends AbsFabActivity { songArtist.setTextSize(TypedValue.COMPLEX_UNIT_PX, smallerTitleBox ? getResources().getDimensionPixelSize(R.dimen.title_box_caption_text_size_small) : getResources().getDimensionPixelSize(R.dimen.title_box_caption_text_size_large)); } - private void setUpPlaybackControllerCard(){ + private void setUpPlaybackControllerCard() { playbackControllerCard.setVisibility(showPlaybackControllerCard ? View.VISIBLE : View.GONE); mediaControllerContainer.setBackgroundColor(showPlaybackControllerCard ? Color.TRANSPARENT : Util.resolveColor(this, R.attr.music_controller_container_color)); } @@ -309,7 +309,7 @@ public class MusicControllerActivity extends AbsFabActivity { protected void onResume() { super.onResume(); updateControllerState(); - startMusicControllerStateUpdateThread(); + startProgressViewsUpdateThread(); updateCurrentSong(); } @@ -429,36 +429,37 @@ public class MusicControllerActivity extends AbsFabActivity { } } - private void startMusicControllerStateUpdateThread() { - killThreads = false; - new Thread(new Runnable() { + private void startProgressViewsUpdateThread() { + if (progressViewsUpdateThread != null) progressViewsUpdateThread.interrupt(); + progressViewsUpdateThread = new Thread(new Runnable() { + int totalMillis = 0; + int progressMillis = 0; + @Override public void run() { - int currentPosition = 0; - int total = 0; - while (!killThreads) { - try { - total = MusicPlayerRemote.getSongDurationMillis(); - currentPosition = MusicPlayerRemote.getSongProgressMillis(); - Thread.sleep(1); - } catch (InterruptedException e) { - return; - } catch (Exception e2) { - e2.printStackTrace(); + try { + while (!Thread.currentThread().isInterrupted()) { + totalMillis = MusicPlayerRemote.getSongDurationMillis(); + progressMillis = MusicPlayerRemote.getSongProgressMillis(); + + runOnUiThread(updateProgressViews); + + Thread.sleep(100); } - final int finalTotal = total; - final int finalCurrentPosition = currentPosition; - runOnUiThread(new Runnable() { - @Override - public void run() { - progressSlider.setMax(finalTotal); - progressSlider.setProgress(finalCurrentPosition); - currentSongProgress.setText(MusicUtil.getReadableDurationString(finalCurrentPosition)); - } - }); + } catch (InterruptedException ignored) { } } - }).start(); + + private Runnable updateProgressViews = new Runnable() { + @Override + public void run() { + progressSlider.setMax(totalMillis); + progressSlider.setProgress(progressMillis); + currentSongProgress.setText(MusicUtil.getReadableDurationString(progressMillis)); + } + }; + }); + progressViewsUpdateThread.start(); } protected void updateControllerState() { @@ -486,7 +487,7 @@ public class MusicControllerActivity extends AbsFabActivity { @Override protected void onPause() { super.onPause(); - killThreads = true; + if(progressViewsUpdateThread != null) progressViewsUpdateThread.interrupt(); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java index a4fd4d8b..e58d8f36 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/ThemeBaseActivity.java @@ -1,7 +1,6 @@ package com.kabouzeid.gramophone.ui.activities.base; import android.app.ActivityManager; -import android.graphics.BitmapFactory; import android.os.Build; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; @@ -22,6 +21,8 @@ public abstract class ThemeBaseActivity extends AppCompatActivity implements Kab private int colorPrimaryDarker; private int colorAccent; + private ActivityManager.TaskDescription taskDescription; + @Override protected void onCreate(Bundle savedInstanceState) { setTheme(PreferenceUtils.getInstance(this).getGeneralTheme()); @@ -49,11 +50,13 @@ public abstract class ThemeBaseActivity extends AppCompatActivity implements Kab protected void notifyTaskColorChange(int color) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { // Sets color of entry in the system recents page - ActivityManager.TaskDescription td = new ActivityManager.TaskDescription( - getString(R.string.app_name), - BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher), - color); - setTaskDescription(td); + if (taskDescription == null || taskDescription.getPrimaryColor() != color) { + taskDescription = new ActivityManager.TaskDescription( + null, + null, + color); + setTaskDescription(taskDescription); + } } } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/Util.java b/app/src/main/java/com/kabouzeid/gramophone/util/Util.java index a883f66a..56d39f9b 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/Util.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/Util.java @@ -10,6 +10,7 @@ import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Build; +import android.support.annotation.AttrRes; import android.support.annotation.ColorInt; import android.support.annotation.DrawableRes; import android.support.v4.content.ContextCompat; @@ -33,8 +34,8 @@ public class Util { // return resId; // } - public static int resolveColor(Context context, int color) { - TypedArray a = context.obtainStyledAttributes(new int[]{color}); + public static int resolveColor(Context context, @AttrRes int colorAttr) { + TypedArray a = context.obtainStyledAttributes(new int[]{colorAttr}); int resId = a.getColor(0, 0); a.recycle(); return resId; diff --git a/app/src/main/java/com/kabouzeid/gramophone/views/DynamicSwitch.java b/app/src/main/java/com/kabouzeid/gramophone/views/DynamicSwitch.java new file mode 100644 index 00000000..12e92c5f --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/views/DynamicSwitch.java @@ -0,0 +1,131 @@ +package com.kabouzeid.gramophone.views; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.graphics.Color; +import android.graphics.PorterDuff; +import android.graphics.drawable.Drawable; +import android.support.v4.content.ContextCompat; +import android.support.v4.graphics.ColorUtils; +import android.support.v4.graphics.drawable.DrawableCompat; +import android.support.v7.internal.widget.ThemeUtils; +import android.support.v7.widget.SwitchCompat; +import android.util.AttributeSet; + +import com.afollestad.materialdialogs.ThemeSingleton; +import com.kabouzeid.gramophone.R; + +import static android.support.v7.internal.widget.ThemeUtils.getThemeAttrColorStateList; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class DynamicSwitch extends SwitchCompat { + static final int[] DISABLED_STATE_SET = new int[]{-android.R.attr.state_enabled}; + static final int[] CHECKED_STATE_SET = new int[]{android.R.attr.state_checked}; + static final int[] EMPTY_STATE_SET = new int[0]; + + public DynamicSwitch(Context context) { + super(context); + init(); + } + + public DynamicSwitch(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public DynamicSwitch(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(); + } + + private void init() { + final int color = ThemeSingleton.get().positiveColor; + setTint(this, color); + } + + public static void setTint(SwitchCompat switchCompat, int color) { + ColorStateList trackColorSl = createSwitchTrackColorStateList(switchCompat.getContext(), color); + ColorStateList thumbColorSl = createSwitchThumbColorStateList(switchCompat.getContext(), color); + + Drawable thumbDrawable = DrawableCompat.wrap(ContextCompat.getDrawable(switchCompat.getContext(), R.drawable.abc_switch_thumb_material)); + DrawableCompat.setTintList(thumbDrawable, thumbColorSl); + DrawableCompat.setTintMode(thumbDrawable, PorterDuff.Mode.MULTIPLY); + switchCompat.setThumbDrawable(thumbDrawable); + + Drawable trackDrawable = DrawableCompat.wrap(ContextCompat.getDrawable(switchCompat.getContext(), R.drawable.abc_switch_track_mtrl_alpha)); + DrawableCompat.setTintList(trackDrawable, trackColorSl); + switchCompat.setTrackDrawable(trackDrawable); + } + + private static ColorStateList createSwitchTrackColorStateList(Context context, int colorActivated) { + final int[][] states = new int[3][]; + final int[] colors = new int[3]; + int i = 0; + + // Disabled state + states[i] = DISABLED_STATE_SET; + colors[i] = getColorWithMultipliedAlpha(ThemeUtils.getThemeAttrColor(context, android.R.attr.colorForeground), 0.1f); + i++; + + states[i] = CHECKED_STATE_SET; + colors[i] = getColorWithMultipliedAlpha(colorActivated, 0.3f); + i++; + + // Default enabled state + states[i] = EMPTY_STATE_SET; + colors[i] = getColorWithMultipliedAlpha(ThemeUtils.getThemeAttrColor(context, android.R.attr.colorForeground), 0.3f); + + return new ColorStateList(states, colors); + } + + private static ColorStateList createSwitchThumbColorStateList(Context context, int colorActivated) { + final int[][] states = new int[3][]; + final int[] colors = new int[3]; + int i = 0; + + final ColorStateList thumbColor = getThemeAttrColorStateList(context, + android.support.v7.appcompat.R.attr.colorSwitchThumbNormal); + + if (thumbColor != null && thumbColor.isStateful()) { + // If colorSwitchThumbNormal is a valid ColorStateList, extract the default and + // disabled colors from it + + // Disabled state + states[i] = DISABLED_STATE_SET; + colors[i] = thumbColor.getColorForState(states[i], 0); + i++; + + states[i] = CHECKED_STATE_SET; + colors[i] = colorActivated; + i++; + + // Default enabled state + states[i] = EMPTY_STATE_SET; + colors[i] = thumbColor.getDefaultColor(); + } else { + // Else we'll use an approximation using the default disabled alpha + + // Disabled state + states[i] = DISABLED_STATE_SET; + colors[i] = ThemeUtils.getDisabledThemeAttrColor(context, android.support.v7.appcompat.R.attr.colorSwitchThumbNormal); + i++; + + states[i] = CHECKED_STATE_SET; + colors[i] = colorActivated; + i++; + + // Default enabled state + states[i] = EMPTY_STATE_SET; + colors[i] = ThemeUtils.getThemeAttrColor(context, android.support.v7.appcompat.R.attr.colorSwitchThumbNormal); + } + + return new ColorStateList(states, colors); + } + + private static int getColorWithMultipliedAlpha(int color, float alpha) { + final int originalAlpha = Color.alpha(color); + return ColorUtils.setAlphaComponent(color, Math.round(originalAlpha * alpha)); + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/preference_custom.xml b/app/src/main/res/layout/preference_color_chooser.xml similarity index 100% rename from app/src/main/res/layout/preference_custom.xml rename to app/src/main/res/layout/preference_color_chooser.xml diff --git a/app/src/main/res/menu/menu_music_playing.xml b/app/src/main/res/menu/menu_music_playing.xml index 2dbe6f08..43685615 100644 --- a/app/src/main/res/menu/menu_music_playing.xml +++ b/app/src/main/res/menu/menu_music_playing.xml @@ -8,10 +8,6 @@ android:icon="@drawable/ic_queue_music_white_24dp" android:title="@string/action_playing_queue" app:showAsAction="ifRoom"/> - + + android:title="@string/equalizer" /> diff --git a/app/src/main/res/xml/pref_colors.xml b/app/src/main/res/xml/pref_colors.xml index 18a2ebee..87f49270 100644 --- a/app/src/main/res/xml/pref_colors.xml +++ b/app/src/main/res/xml/pref_colors.xml @@ -9,7 +9,6 @@ android:key="general_theme" android:negativeButtonText="@null" android:positiveButtonText="@null" - android:layout="@layout/preference_custom" android:title="@string/pref_title_general_theme" /> + android:summary="@string/pref_summary_colored_navigation_bar" /> diff --git a/app/src/main/res/xml/pref_general.xml b/app/src/main/res/xml/pref_general.xml index 6445329e..4f753d85 100644 --- a/app/src/main/res/xml/pref_general.xml +++ b/app/src/main/res/xml/pref_general.xml @@ -9,7 +9,6 @@ android:key="default_start_page" android:negativeButtonText="@null" android:positiveButtonText="@null" - android:layout="@layout/preference_custom" android:title="@string/pref_title_set_default_start_page" /> diff --git a/app/src/main/res/xml/pref_now_playing_screen.xml b/app/src/main/res/xml/pref_now_playing_screen.xml index 33c41041..ca970d94 100644 --- a/app/src/main/res/xml/pref_now_playing_screen.xml +++ b/app/src/main/res/xml/pref_now_playing_screen.xml @@ -6,7 +6,6 @@ @@ -15,7 +14,6 @@ android:defaultValue="false" android:dependency="opaque_statusbar_now_playing" android:key="opaque_toolbar_now_playing" - android:layout="@layout/preference_custom" android:summary="@string/pref_summary_opaque_toolbar_now_playing" android:title="@string/pref_title_opaque_toolbar_now_playing" android:widgetLayout="@layout/preference_dynamic_checkbox" /> @@ -23,7 +21,6 @@ @@ -31,7 +28,6 @@ @@ -39,7 +35,6 @@ @@ -47,7 +42,6 @@