seekbar crash fix

This commit is contained in:
Gavriil Sitnikov 2015-11-26 02:20:00 +03:00
parent 9e4cb9b885
commit 1575aab04d
2 changed files with 93 additions and 41 deletions

View File

@ -26,9 +26,17 @@ import android.os.Handler;
import android.provider.Settings; import android.provider.Settings;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.widget.ImageView; import android.view.View;
import android.widget.SeekBar; import android.widget.SeekBar;
import org.roboswag.core.log.Lc;
import org.roboswag.core.utils.ShouldNotHappenException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import rx.Observable; import rx.Observable;
import rx.Subscription; import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers; import rx.android.schedulers.AndroidSchedulers;
@ -58,14 +66,8 @@ public final class VolumeController {
private final BehaviorSubject<Integer> volumeSubject; private final BehaviorSubject<Integer> volumeSubject;
private final Observable<Integer> volumeObservable; private final Observable<Integer> volumeObservable;
@Nullable private final Map<SeekBar, Subscription> seekBars = new HashMap<>();
private SeekBar seekBar; private final Set<VolumeButtons> volumeButtonsSet = new HashSet<>();
@Nullable
private ImageView volumeDown;
@Nullable
private ImageView volumeUp;
@Nullable
private Subscription seekBarSubscription;
private VolumeController(@NonNull final Context context) { private VolumeController(@NonNull final Context context) {
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
@ -85,15 +87,17 @@ public final class VolumeController {
} }
private void updateVolume() { private void updateVolume() {
volumeSubject.onNext(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)); volumeSubject.onNext(getVolume());
} }
public void setVolume(final int value) { public void setVolume(final int value) {
if (value < 0 || value > maxVolume) { if (value < 0 || value > maxVolume) {
throw new IllegalStateException("Volume: " + value + " out of bounds [0," + maxVolume + "]"); Lc.fatalException(new ShouldNotHappenException("Volume: " + value + " out of bounds [0," + maxVolume + "]"));
return;
} }
if (getVolume() != value) { if (getVolume() != value) {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, value, 0); audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, value, 0);
updateVolume();
} }
} }
@ -107,13 +111,13 @@ public final class VolumeController {
} }
public void attachSeekBar(@NonNull final SeekBar seekBar) { public void attachSeekBar(@NonNull final SeekBar seekBar) {
if (this.seekBar != null) { if (seekBars.containsKey(seekBar)) {
throw new IllegalArgumentException("Attached SeekBar is not null"); Lc.fatalException(new ShouldNotHappenException("SeekBar already attached"));
return;
} }
this.seekBar = seekBar; seekBar.setMax(maxVolume);
this.seekBar.setMax(maxVolume); seekBar.setProgress(getVolume());
this.seekBar.setProgress(getVolume()); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
this.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override @Override
public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) { public void onProgressChanged(final SeekBar seekBar, final int progress, final boolean fromUser) {
@ -132,52 +136,81 @@ public final class VolumeController {
}); });
seekBarSubscription = observeVolume() seekBars.put(seekBar, observeVolume()
.subscribeOn(AndroidSchedulers.mainThread()) .subscribeOn(AndroidSchedulers.mainThread())
.subscribe(seekBar::setProgress); .subscribe(seekBar::setProgress));
} }
public void detachSeekBar(@NonNull final SeekBar seekBar) { public void detachSeekBar(@NonNull final SeekBar seekBar) {
if (this.seekBar != seekBar) { final Subscription subscription = seekBars.get(seekBar);
throw new IllegalArgumentException("Wrong SeekBar: " + seekBar + " != " + this.seekBar); if (subscription == null) {
Lc.fatalException(new ShouldNotHappenException("SeekBar not attached yet"));
return;
} }
if (seekBarSubscription == null) { seekBar.setOnSeekBarChangeListener(null);
throw new IllegalStateException("SeekBarSubscription is null on detach of SeekBar"); subscription.unsubscribe();
} seekBars.remove(seekBar);
this.seekBar.setOnSeekBarChangeListener(null);
seekBarSubscription.unsubscribe();
seekBarSubscription = null;
this.seekBar = null;
} }
public void attachVolumeButtons(@NonNull final ImageView volumeDown, @NonNull final ImageView volumeUp) { @SuppressWarnings("PMD.AccessorClassGeneration")
if (this.volumeDown != null && this.volumeUp != null) { public void attachVolumeButtons(@NonNull final View volumeUpButton, @NonNull final View volumeDownButton) {
throw new IllegalArgumentException("Attached volume buttons is not null"); final VolumeButtons volumeButtons = new VolumeButtons(volumeUpButton, volumeDownButton);
if (volumeButtonsSet.contains(volumeButtons)) {
Lc.fatalException(new ShouldNotHappenException("VolumeButtons already attached"));
return;
} }
this.volumeDown = volumeDown;
this.volumeUp = volumeUp;
volumeUp.setOnClickListener(v -> { volumeButtons.volumeUpButton.setOnClickListener(v -> {
if (getVolume() != maxVolume) { if (getVolume() != maxVolume) {
setVolume(getVolume() + 1); setVolume(getVolume() + 1);
} }
}); });
volumeDown.setOnClickListener(v -> { volumeButtons.volumeDownButton.setOnClickListener(v -> {
if (getVolume() != 0) { if (getVolume() != 0) {
setVolume(getVolume() - 1); setVolume(getVolume() - 1);
} }
}); });
volumeButtonsSet.add(volumeButtons);
} }
public void detachVolumeButtons(@NonNull final ImageView volumeDownImageView, @NonNull final ImageView volumeUpImageView) { @SuppressWarnings("PMD.AccessorClassGeneration")
if (this.volumeDown != volumeDownImageView && this.volumeUp != volumeUpImageView) { public void detachVolumeButtons(@NonNull final View volumeUpButton, @NonNull final View volumeDownButton) {
throw new IllegalArgumentException("Wrong SeekBar: " + seekBar + " != " + this.seekBar); final VolumeButtons volumeButtons = new VolumeButtons(volumeUpButton, volumeDownButton);
if (!volumeButtonsSet.contains(volumeButtons)) {
Lc.fatalException(new ShouldNotHappenException("VolumeButtons not attached yet"));
return;
}
volumeButtons.volumeUpButton.setOnClickListener(null);
volumeButtons.volumeDownButton.setOnClickListener(null);
volumeButtonsSet.remove(volumeButtons);
}
private static class VolumeButtons {
@NonNull
private final View volumeUpButton;
@NonNull
private final View volumeDownButton;
private VolumeButtons(@NonNull final View volumeUpButton, @NonNull final View volumeDownButton) {
this.volumeUpButton = volumeUpButton;
this.volumeDownButton = volumeDownButton;
}
@Override
public boolean equals(final Object object) {
return object instanceof VolumeButtons
&& ((VolumeButtons) object).volumeDownButton == volumeDownButton
&& ((VolumeButtons) object).volumeUpButton == volumeUpButton;
}
@Override
public int hashCode() {
return volumeDownButton.hashCode() + volumeUpButton.hashCode();
} }
this.volumeDown = null;
this.volumeUp = null;
} }
private class VolumeObserver extends ContentObserver { private class VolumeObserver extends ContentObserver {

View File

@ -19,6 +19,9 @@
package org.roboswag.components.navigation; package org.roboswag.components.navigation;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
@ -62,6 +65,22 @@ public abstract class AbstractBaseActivity extends AppCompatActivity
return topFragmentTag != null && topFragmentTag.contains(TOP_FRAGMENT_TAG_MARK); return topFragmentTag != null && topFragmentTag.contains(TOP_FRAGMENT_TAG_MARK);
} }
// https://code.google.com/p/android/issues/detail?id=2373
// https://github.com/cleverua/android_startup_activity
// http://stackoverflow.com/questions/4341600/how-to-prevent-multiple-instances-of-an-activity-when-it-is-launched-with-differ
@SuppressWarnings("deprecation")
public boolean isLaunchedManyTimes() {
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (final ActivityManager.RunningTaskInfo taskInfo : activityManager.getRunningTasks(Integer.MAX_VALUE)) {
if (getPackageName().equals(taskInfo.baseActivity.getPackageName())
&& taskInfo.numActivities > 1
&& Intent.ACTION_MAIN.equals(getIntent().getAction())) {
return true;
}
}
return false;
}
@Override @Override
protected void onCreate(@Nullable final Bundle savedInstanceState) { protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);