add getVolume to playback interface and improve progress handler
This commit is contained in:
parent
b1ffa78a2e
commit
2c8229b0dc
4 changed files with 61 additions and 58 deletions
|
|
@ -2,10 +2,10 @@ package com.dkanada.gramophone.service;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Environment;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.dkanada.gramophone.App;
|
||||||
import com.dkanada.gramophone.R;
|
import com.dkanada.gramophone.R;
|
||||||
import com.dkanada.gramophone.model.Song;
|
import com.dkanada.gramophone.model.Song;
|
||||||
import com.dkanada.gramophone.service.playback.Playback;
|
import com.dkanada.gramophone.service.playback.Playback;
|
||||||
|
|
@ -118,7 +118,8 @@ public class MultiPlayer implements Playback {
|
||||||
LeastRecentlyUsedCacheEvictor recentlyUsedCache = new LeastRecentlyUsedCacheEvictor(Long.MAX_VALUE);
|
LeastRecentlyUsedCacheEvictor recentlyUsedCache = new LeastRecentlyUsedCacheEvictor(Long.MAX_VALUE);
|
||||||
ExoDatabaseProvider databaseProvider = new ExoDatabaseProvider(context);
|
ExoDatabaseProvider databaseProvider = new ExoDatabaseProvider(context);
|
||||||
|
|
||||||
simpleCache = new SimpleCache(new File(Environment.getExternalStorageDirectory() + "/Gelli/cache"), recentlyUsedCache, databaseProvider);
|
File file = new File(App.getInstance().getApplicationInfo().dataDir + "/Gelli/exoplayer");
|
||||||
|
simpleCache = new SimpleCache(file, recentlyUsedCache, databaseProvider);
|
||||||
dataSource = buildDataSourceFactory();
|
dataSource = buildDataSourceFactory();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -184,12 +185,7 @@ public class MultiPlayer implements Playback {
|
||||||
.createMediaSource(uri);
|
.createMediaSource(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mediaSource.getSize() < position) {
|
mediaSource.addMediaSource(Math.min(mediaSource.getSize(), position), source);
|
||||||
mediaSource.addMediaSource(mediaSource.getSize(), source);
|
|
||||||
} else {
|
|
||||||
mediaSource.addMediaSource(position, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (position == 0) start();
|
if (position == 0) start();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -247,7 +243,7 @@ public class MultiPlayer implements Playback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPosition() {
|
public int getProgress() {
|
||||||
if (!isReady) return -1;
|
if (!isReady) return -1;
|
||||||
return (int) exoPlayer.getCurrentPosition();
|
return (int) exoPlayer.getCurrentPosition();
|
||||||
}
|
}
|
||||||
|
|
@ -259,7 +255,7 @@ public class MultiPlayer implements Playback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPosition(int position) {
|
public void setProgress(int position) {
|
||||||
exoPlayer.seekTo(position);
|
exoPlayer.seekTo(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -267,4 +263,9 @@ public class MultiPlayer implements Playback {
|
||||||
public void setVolume(int volume) {
|
public void setVolume(int volume) {
|
||||||
exoPlayer.setVolume(volume / 100f);
|
exoPlayer.setVolume(volume / 100f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVolume() {
|
||||||
|
return (int) (exoPlayer.getVolume() * 100);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,8 +63,10 @@ import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Timer;
|
import java.util.concurrent.Executors;
|
||||||
import java.util.TimerTask;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class MusicService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks {
|
public class MusicService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener, Playback.PlaybackCallbacks {
|
||||||
public static final String PHONOGRAPH_PACKAGE_NAME = "com.dkanada.gramophone";
|
public static final String PHONOGRAPH_PACKAGE_NAME = "com.dkanada.gramophone";
|
||||||
|
|
@ -78,7 +80,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
public static final String ACTION_REWIND = PHONOGRAPH_PACKAGE_NAME + ".rewind";
|
public static final String ACTION_REWIND = PHONOGRAPH_PACKAGE_NAME + ".rewind";
|
||||||
public static final String ACTION_QUIT = PHONOGRAPH_PACKAGE_NAME + ".quitservice";
|
public static final String ACTION_QUIT = PHONOGRAPH_PACKAGE_NAME + ".quitservice";
|
||||||
public static final String ACTION_PENDING_QUIT = PHONOGRAPH_PACKAGE_NAME + ".pendingquitservice";
|
public static final String ACTION_PENDING_QUIT = PHONOGRAPH_PACKAGE_NAME + ".pendingquitservice";
|
||||||
public static final String INTENT_EXTRA_PLAYLIST = PHONOGRAPH_PACKAGE_NAME + "intentextra.playlist";
|
public static final String INTENT_EXTRA_PLAYLIST = PHONOGRAPH_PACKAGE_NAME + ".intentextra.playlist";
|
||||||
public static final String INTENT_EXTRA_SHUFFLE_MODE = PHONOGRAPH_PACKAGE_NAME + ".intentextra.shufflemode";
|
public static final String INTENT_EXTRA_SHUFFLE_MODE = PHONOGRAPH_PACKAGE_NAME + ".intentextra.shufflemode";
|
||||||
|
|
||||||
public static final String APP_WIDGET_UPDATE = PHONOGRAPH_PACKAGE_NAME + ".appwidgetupdate";
|
public static final String APP_WIDGET_UPDATE = PHONOGRAPH_PACKAGE_NAME + ".appwidgetupdate";
|
||||||
|
|
@ -101,7 +103,6 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
public static final int FOCUS_CHANGE = 6;
|
public static final int FOCUS_CHANGE = 6;
|
||||||
public static final int DUCK = 7;
|
public static final int DUCK = 7;
|
||||||
public static final int UNDUCK = 8;
|
public static final int UNDUCK = 8;
|
||||||
public static final int RESTORE_QUEUES = 9;
|
|
||||||
|
|
||||||
public static final int SHUFFLE_MODE_NONE = 0;
|
public static final int SHUFFLE_MODE_NONE = 0;
|
||||||
public static final int SHUFFLE_MODE_SHUFFLE = 1;
|
public static final int SHUFFLE_MODE_SHUFFLE = 1;
|
||||||
|
|
@ -111,6 +112,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
public static final int REPEAT_MODE_THIS = 2;
|
public static final int REPEAT_MODE_THIS = 2;
|
||||||
|
|
||||||
public static final int SAVE_QUEUE = 0;
|
public static final int SAVE_QUEUE = 0;
|
||||||
|
public static final int LOAD_QUEUE = 9;
|
||||||
|
|
||||||
private final IBinder musicBinder = new MusicBinder();
|
private final IBinder musicBinder = new MusicBinder();
|
||||||
|
|
||||||
|
|
@ -121,10 +123,13 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
private AppWidgetClassic appWidgetClassic = AppWidgetClassic.getInstance();
|
private AppWidgetClassic appWidgetClassic = AppWidgetClassic.getInstance();
|
||||||
|
|
||||||
private Playback playback;
|
private Playback playback;
|
||||||
|
|
||||||
private List<Song> playingQueue = new ArrayList<>();
|
private List<Song> playingQueue = new ArrayList<>();
|
||||||
private List<Song> originalPlayingQueue = new ArrayList<>();
|
private List<Song> originalPlayingQueue = new ArrayList<>();
|
||||||
|
|
||||||
private int position = -1;
|
private int position = -1;
|
||||||
private int nextPosition = -1;
|
private int nextPosition = -1;
|
||||||
|
|
||||||
private int shuffleMode;
|
private int shuffleMode;
|
||||||
private int repeatMode;
|
private int repeatMode;
|
||||||
private boolean queuesRestored;
|
private boolean queuesRestored;
|
||||||
|
|
@ -146,6 +151,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
private ThrottledSeekHandler throttledSeekHandler;
|
private ThrottledSeekHandler throttledSeekHandler;
|
||||||
private QueueSaveHandler queueSaveHandler;
|
private QueueSaveHandler queueSaveHandler;
|
||||||
private ProgressHandler progressHandler;
|
private ProgressHandler progressHandler;
|
||||||
|
|
||||||
private HandlerThread playerHandlerThread;
|
private HandlerThread playerHandlerThread;
|
||||||
private HandlerThread queueSaveHandlerThread;
|
private HandlerThread queueSaveHandlerThread;
|
||||||
|
|
||||||
|
|
@ -176,16 +182,13 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
|
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
|
||||||
wakeLock.setReferenceCounted(false);
|
wakeLock.setReferenceCounted(false);
|
||||||
|
|
||||||
|
playback = new MultiPlayer(this);
|
||||||
|
playback.setCallbacks(this);
|
||||||
|
|
||||||
playerHandlerThread = new HandlerThread(PlaybackHandler.class.getName());
|
playerHandlerThread = new HandlerThread(PlaybackHandler.class.getName());
|
||||||
playerHandlerThread.start();
|
playerHandlerThread.start();
|
||||||
playerHandler = new PlaybackHandler(this, playerHandlerThread.getLooper());
|
playerHandler = new PlaybackHandler(this, playerHandlerThread.getLooper());
|
||||||
|
|
||||||
playback = new MultiPlayer(this);
|
|
||||||
playback.setCallbacks(this);
|
|
||||||
|
|
||||||
initMediaSession();
|
|
||||||
|
|
||||||
// queue saving needs to run on a separate thread so that it doesn't block the playback handler events
|
|
||||||
queueSaveHandlerThread = new HandlerThread(QueueSaveHandler.class.getName(), Process.THREAD_PRIORITY_BACKGROUND);
|
queueSaveHandlerThread = new HandlerThread(QueueSaveHandler.class.getName(), Process.THREAD_PRIORITY_BACKGROUND);
|
||||||
queueSaveHandlerThread.start();
|
queueSaveHandlerThread.start();
|
||||||
queueSaveHandler = new QueueSaveHandler(this, queueSaveHandlerThread.getLooper());
|
queueSaveHandler = new QueueSaveHandler(this, queueSaveHandlerThread.getLooper());
|
||||||
|
|
@ -200,6 +203,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this);
|
PreferenceUtil.getInstance(this).registerOnSharedPreferenceChangedListener(this);
|
||||||
|
|
||||||
initNotification();
|
initNotification();
|
||||||
|
initMediaSession();
|
||||||
restoreState();
|
restoreState();
|
||||||
|
|
||||||
mediaSession.setActive(true);
|
mediaSession.setActive(true);
|
||||||
|
|
@ -388,8 +392,8 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
notifyChange(SHUFFLE_MODE_CHANGED);
|
notifyChange(SHUFFLE_MODE_CHANGED);
|
||||||
notifyChange(REPEAT_MODE_CHANGED);
|
notifyChange(REPEAT_MODE_CHANGED);
|
||||||
|
|
||||||
playerHandler.removeMessages(RESTORE_QUEUES);
|
playerHandler.removeMessages(LOAD_QUEUE);
|
||||||
playerHandler.sendEmptyMessage(RESTORE_QUEUES);
|
playerHandler.sendEmptyMessage(LOAD_QUEUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void restoreQueuesAndPositionIfNecessary() {
|
private synchronized void restoreQueuesAndPositionIfNecessary() {
|
||||||
|
|
@ -843,7 +847,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSongProgressMillis() {
|
public int getSongProgressMillis() {
|
||||||
return playback.getPosition();
|
return playback.getProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSongDurationMillis() {
|
public int getSongDurationMillis() {
|
||||||
|
|
@ -861,7 +865,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
|
|
||||||
public int seek(int millis) {
|
public int seek(int millis) {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
playback.setPosition(millis);
|
playback.setProgress(millis);
|
||||||
throttledSeekHandler.notifySeek();
|
throttledSeekHandler.notifySeek();
|
||||||
return millis;
|
return millis;
|
||||||
}
|
}
|
||||||
|
|
@ -1112,7 +1116,7 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
service.prepareNextImpl();
|
service.prepareNextImpl();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RESTORE_QUEUES:
|
case LOAD_QUEUE:
|
||||||
service.restoreQueuesAndPositionIfNecessary();
|
service.restoreQueuesAndPositionIfNecessary();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1196,33 +1200,29 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
saveProgress();
|
|
||||||
notifyChange(PLAY_STATE_CHANGED);
|
notifyChange(PLAY_STATE_CHANGED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class ProgressHandler extends Handler {
|
private static final class ProgressHandler extends Handler {
|
||||||
private WeakReference<MusicService> mService;
|
private WeakReference<MusicService> mService;
|
||||||
private Timer mTimer;
|
|
||||||
|
private ScheduledExecutorService executorService;
|
||||||
|
private Future<?> task;
|
||||||
|
|
||||||
public ProgressHandler(MusicService service, Looper looper) {
|
public ProgressHandler(MusicService service, Looper looper) {
|
||||||
super(looper);
|
super(looper);
|
||||||
|
|
||||||
mService = new WeakReference<>(service);
|
mService = new WeakReference<>(service);
|
||||||
mTimer = new Timer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleMessage(@NonNull final Message msg) {
|
public void handleMessage(@NonNull final Message msg) {
|
||||||
final MusicService service = mService.get();
|
|
||||||
if (service == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (msg.what) {
|
switch (msg.what) {
|
||||||
case PLAY_SONG:
|
case PLAY_SONG:
|
||||||
case TRACK_WENT_TO_NEXT:
|
|
||||||
onStart();
|
onStart();
|
||||||
|
case TRACK_WENT_TO_NEXT:
|
||||||
|
onNext();
|
||||||
break;
|
break;
|
||||||
case TRACK_ENDED:
|
case TRACK_ENDED:
|
||||||
onStop();
|
onStop();
|
||||||
|
|
@ -1230,20 +1230,21 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
|
if (executorService != null) executorService.shutdownNow();
|
||||||
|
|
||||||
|
executorService = Executors.newScheduledThreadPool(1);
|
||||||
|
task = executorService.scheduleAtFixedRate(this::onProgress, 10, 10, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onNext() {
|
||||||
PlaybackStartInfo startInfo = new PlaybackStartInfo();
|
PlaybackStartInfo startInfo = new PlaybackStartInfo();
|
||||||
TimerTask mTask = new TimerTask() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
onProgress();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
startInfo.setItemId(mService.get().getCurrentSong().id);
|
startInfo.setItemId(mService.get().getCurrentSong().id);
|
||||||
|
startInfo.setVolumeLevel(mService.get().playback.getVolume());
|
||||||
startInfo.setCanSeek(true);
|
startInfo.setCanSeek(true);
|
||||||
startInfo.setIsPaused(false);
|
startInfo.setIsPaused(false);
|
||||||
|
|
||||||
App.getApiClient().ReportPlaybackStartAsync(startInfo, new EmptyResponse());
|
App.getApiClient().ReportPlaybackStartAsync(startInfo, new EmptyResponse());
|
||||||
mTimer.schedule(mTask, 10000, 10000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onProgress() {
|
public void onProgress() {
|
||||||
|
|
@ -1252,26 +1253,26 @@ public class MusicService extends Service implements SharedPreferences.OnSharedP
|
||||||
// TODO these cause a wrong thread error
|
// TODO these cause a wrong thread error
|
||||||
long progress = mService.get().getSongProgressMillis();
|
long progress = mService.get().getSongProgressMillis();
|
||||||
double duration = mService.get().getSongDurationMillis();
|
double duration = mService.get().getSongDurationMillis();
|
||||||
if (progress / duration > 0.9) onStop();
|
if (progress / duration > 0.9) {
|
||||||
|
Song current = mService.get().getCurrentSong();
|
||||||
|
String user = App.getApiClient().getCurrentUserId();
|
||||||
|
Date time = new Date(System.currentTimeMillis());
|
||||||
|
|
||||||
|
App.getApiClient().MarkPlayedAsync(current.id, user, time, new Response<>());
|
||||||
|
}
|
||||||
|
|
||||||
progressInfo.setItemId(mService.get().getCurrentSong().id);
|
progressInfo.setItemId(mService.get().getCurrentSong().id);
|
||||||
progressInfo.setPositionTicks(progress * 10000);
|
progressInfo.setPositionTicks(progress * 10000);
|
||||||
progressInfo.setCanSeek(true);
|
progressInfo.setVolumeLevel(mService.get().playback.getVolume());
|
||||||
progressInfo.setIsPaused(!mService.get().playback.isPlaying());
|
progressInfo.setIsPaused(!mService.get().playback.isPlaying());
|
||||||
|
progressInfo.setCanSeek(true);
|
||||||
|
|
||||||
App.getApiClient().ensureWebSocket();
|
|
||||||
App.getApiClient().ReportPlaybackProgressAsync(progressInfo, new EmptyResponse());
|
App.getApiClient().ReportPlaybackProgressAsync(progressInfo, new EmptyResponse());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
mTimer.purge();
|
task.cancel(true);
|
||||||
|
executorService.shutdownNow();
|
||||||
Song current = mService.get().getCurrentSong();
|
|
||||||
String user = App.getApiClient().getCurrentUserId();
|
|
||||||
Date time = new Date(System.currentTimeMillis());
|
|
||||||
|
|
||||||
if (current == Song.EMPTY_SONG) return;
|
|
||||||
App.getApiClient().MarkPlayedAsync(current.id, user, time, new Response<>());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,14 +19,16 @@ public interface Playback {
|
||||||
|
|
||||||
boolean isPlaying();
|
boolean isPlaying();
|
||||||
|
|
||||||
int getPosition();
|
int getProgress();
|
||||||
|
|
||||||
int getDuration();
|
int getDuration();
|
||||||
|
|
||||||
void setPosition(int position);
|
void setProgress(int position);
|
||||||
|
|
||||||
void setVolume(int volume);
|
void setVolume(int volume);
|
||||||
|
|
||||||
|
int getVolume();
|
||||||
|
|
||||||
interface PlaybackCallbacks {
|
interface PlaybackCallbacks {
|
||||||
void onTrackStarted();
|
void onTrackStarted();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,16 +55,16 @@ public class SplashActivity extends AbsBaseActivity {
|
||||||
builder.setMessage(R.string.battery_optimizations_message)
|
builder.setMessage(R.string.battery_optimizations_message)
|
||||||
.setTitle(R.string.battery_optimizations_title)
|
.setTitle(R.string.battery_optimizations_title)
|
||||||
.setNegativeButton(R.string.ignore, (dialog, id) -> login())
|
.setNegativeButton(R.string.ignore, (dialog, id) -> login())
|
||||||
.setPositiveButton(R.string.disable, (dialog, id) -> openPowerSettings(SplashActivity.this))
|
.setPositiveButton(R.string.disable, (dialog, id) -> openPowerSettings())
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||||
private void openPowerSettings(Context context) {
|
private void openPowerSettings() {
|
||||||
Intent intent = new Intent();
|
Intent intent = new Intent();
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
|
||||||
context.startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void login() {
|
public void login() {
|
||||||
|
|
@ -102,6 +102,5 @@ public class SplashActivity extends AbsBaseActivity {
|
||||||
Intent intent = new Intent(this, LoginActivity.class);
|
Intent intent = new Intent(this, LoginActivity.class);
|
||||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue