I have an audio app with a MediaBrowserService. To update the SeekBar in the Activity, I have a Runnable in the service that updates the MediaSession extras every 250 milliseconds (this is to ensure the SeekBar movement isn't janky).
Everything works fine except a small number of users are reporting that after a couple of minutes the playback consistently cuts out. The logs don't show that onDestroy or onPause or onStop of the MediaSessionCompat.Callback is called or any of the error handling. It just stops. However, I'm unable to recreate it myself. Once the audio starts there is nothing running in the service but this. Is it possible updating the SeekBar this way is causing the playback to stop?
public class MediaPlayerService extends MediaBrowserServiceCompat {
private Handler mMediaHandler;
private MediaSessionCompat mMediaSessionCompat;
private ExoPlayer player;
#Override
public void onCreate() {
super.onCreate();
mMediaSessionCompat = new MediaSessionCompat(this, MediaPlayerService.class.getSimpleName());
mMediaSessionCompat.setCallback(mMediaSessionCallback);
}
public void PlayAudio()
{
player = new ExoPlayer.Builder(this).build();
player.setMediaItem(MediaItem.fromUri(uri), position);
player.prepare();
player.play();
mMediaHandler = new Handler(Looper.getMainLooper());
mMediaHandler.post(mUpdateMediaPosition);
}
Runnable mUpdateMediaPosition = new Runnable() {
public void run() {
final Bundle extras = new Bundle();
extras.putInt("position", player.getCurrentPosition());
mMediaSessionCompat.setExtras(extras);
mMediaHandler.postDelayed(this, 250);
}
};
}
public class MediaActivity
{
private MediaBrowserCompat mMediaBrowserCompat;
private MediaControllerCompat mMediaController;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMediaBrowserCompat = new MediaBrowserCompat(
getApplicationContext(),
new ComponentName(mContext, MediaPlayerService.class),
mMediaBrowserCompatConnectionCallback,
getIntent().getExtras());
mMediaBrowserCompat.connect();
}
MediaControllerCompat.Callback mMediaControllerCompatCallback = new MediaControllerCompat.Callback() {
#Override
public void onExtrasChanged(Bundle extras) {
super.onExtrasChanged(extras);
int position = extras.getInt("position");
seekBar.setProgress(position);
}
}
MediaBrowserCompat.ConnectionCallback mMediaBrowserCompatConnectionCallback = new MediaBrowserCompat.ConnectionCallback() {
#Override
public void onConnected() {
super.onConnected();
mMediaController = new MediaControllerCompat(mContext, mMediaBrowserCompat.getSessionToken());
mMediaController.registerCallback(mMediaControllerCompatCallback);
}
};
}
Answering my own question in case it helps anyone in the future but connecting to a MediaBrowserService does not actually start the service. You have to call startService in the MediaBrowserService (the documentation recommends when playback starts) or the MediaBrowserService will stop when all connections to it disconnect.
Related
I'm using ExoPlayer to play some mp4's from a URL. When the user click's the home button, or anything that causes the app to be removed from the user's view and then comes back to my app (and video activity) I want the video to resume where it left off. I tried implementing this by saving the video position in onStop() and then rebuilding the player and using seekTo() in onStart(). I have a check to see if my current exoplayer is null in onStart(), this check never passes however, so I think this is where the problem lies. How it's coded now my video never resumes. If I leave the app by pressing the home button onStop() gets called and then onStart() will get called when I go back into my app, however the video player remains black and never plays the video. If I remove the null check I get two instances of the video playing whenever I start a video from the main activity because it gets called both in onCreate() and onStart(). Is there a better method for getting the functionality that I want? Any help is appreciated!
public class VideoActivity extends AppCompatActivity {
private SimpleExoPlayer exoPlayer;
private SimpleExoPlayerView simpleExoPlayerView;
private long playerPosition;
private String mp4Url;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.player_activity);
// Get the Intent that started this activity and extract the video url
Intent intent = getIntent();
mp4Url = intent.getStringExtra(MainActivity.VIDEO_URL);
// Create an exoplayer instance and start playing video
buildPlayer(mp4Url);
}
private void buildPlayer(String mp4Url) {
// Create a default TrackSelector
Handler mainHandler = new Handler();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
// Create the player
exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector); // no LoadControl?
simpleExoPlayerView = new SimpleExoPlayerView(this);
simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
// Set media controller
simpleExoPlayerView.setUseController(true);
simpleExoPlayerView.requestFocus();
// Bind player to the view
simpleExoPlayerView.setPlayer(exoPlayer);
// Create Uri from video location
// TODO: should this be in some network class? Should I be appending APIKEY here?
Uri mp4Uri = Uri.parse(mp4Url + "?api_key=" + BuildConfig.GIANTBOMB_API_KEY);
Timber.v("Video url with api key: " + mp4Uri.toString());
// Create another bandwidth meter for bandwidth during playback (not strictly necessary)
DefaultBandwidthMeter playbackBandwidthMeter = new DefaultBandwidthMeter();
// DataSourceFactory to produce DataSource instances through which media data is loaded
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(this,
Util.getUserAgent(this, "GiantBombForAndroid"),
playbackBandwidthMeter);
// Produces Extractor instances for parsing the media data
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
ExtractorMediaSource.EventListener eventListener = new ExtractorMediaSource.EventListener() {
#Override
public void onLoadError(IOException error) {
Timber.e("Error loading video from source");
}
};
final MediaSource videoSource = new ExtractorMediaSource(mp4Uri,
dataSourceFactory,
extractorsFactory,
mainHandler,
eventListener);
exoPlayer.prepare(videoSource);
exoPlayer.addListener(new ExoPlayer.EventListener() {
#Override
public void onLoadingChanged(boolean isLoading) {
Timber.v("Listener-onLoadingChanged...");
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
Timber.v("Listener-onPlayerStateChanged...");
}
#Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
Timber.v("Listener-onTimelineChanged...");
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
// TODO: Do I need anything here?
}
#Override
public void onPlayerError(ExoPlaybackException error) {
Timber.v("Listener-onPlayerError...");
exoPlayer.stop();
exoPlayer.prepare(videoSource);
exoPlayer.setPlayWhenReady(true);
}
#Override
public void onPositionDiscontinuity() {
Timber.v("Listener-onPositionDiscontinuity...");
}
#Override
public void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
// TODO: Do I need anything here?
}
});
exoPlayer.setPlayWhenReady(true);
}
#Override
protected void onStart() {
super.onStart();
Timber.v("onStart()...");
if (exoPlayer == null) {
Timber.v("No exoplayer instance, recreating...");
buildPlayer(mp4Url);
exoPlayer.seekTo(playerPosition);
}
}
#Override
protected void onStop(){
super.onStop();
Timber.v("onStop()...");
//TODO: pull player creation code into it's own method so it can be called here as well
playerPosition = exoPlayer.getCurrentPosition();
exoPlayer.release();
}
#Override
protected void onDestroy() {
super.onDestroy();
Timber.v("onDestroy()...");
exoPlayer.release();
}
}
Currently you're calling release in onStop() which will null out all the important pieces of the player, but not the exoPlayer field (and destroy any state that you aren't keeping track of yourself).
There are a few different approaches. But no matter what you do, you'll likely want to keep track of some state yourself. Below I use them as fields, but they could also be placed in onSavedInstanceState(). In onStop() we're saving off two pieces of information and then pulling them out in onStart(). 1) The last position our player was in when pausing and 2) whether we should play when resumed. You can likely move your seekTo call out of the if == null block since you'll probably always want to resume from where you left off.:
#Override
public void onStart() {
// ...
if (exoPlayer == null) {
// init player
}
// Seek to the last position of the player.
exoPlayer.seekTo(mLastPosition);
// Put the player into the last state we were in.
exoPlayer.setPlayWhenReady(mPlayVideoWhenForegrounded);
// ...
}
#Override
public void onStop() {
// ...
// Store off if we were playing so we know if we should start when we're foregrounded again.
mPlayVideoWhenForegrounded = exoPlayer.getPlayWhenReady();
// Store off the last position our player was in before we paused it.
mLastPosition = exoPlayer.getCurrentPosition();
// Pause the player
exoPlayer.setPlayWhenReady(false);
// ...
}
Now the other issue I see with your code sample is that exoPlayer.release() won't null out the field exoPlayer. So you could additionally add the line exoPlayer = null after exoPlayer.release() which should hopefully fix your issue of multiple exoPlayers. You could also move the release() call to onDestroy() but only if you know you're reinstantiating everything correctly.
There is no need to reinit player again. The following code is pretty enough:
#Override
protected void onPause() {
super.onPause();
if (player!=null) {
player.stop();
mLastPosition = player.getCurrentPosition();
}
}
#Override
protected void onResume() {
super.onResume();
//initiatePlayer();
if(mLastPosition!=0 && player!=null){
player.seekTo(mLastPosition);
}
}
Try the following
Get the player position in onPause.
initiate the palyer again in onResume and set seek to the last position of the player
private void initiatePlayer() {
try {
exoPlayer = ExoPlayerFactory.newSimpleInstance(this);
DataSource.Factory dataSourceFactory =
new DefaultDataSourceFactory(this, Util.getUserAgent(this, this.getResources().getString(R.string.app_name)));
DefaultExtractorsFactory extractorsFactory =
new DefaultExtractorsFactory()
.setMp4ExtractorFlags(Mp4Extractor.FLAG_WORKAROUND_IGNORE_EDIT_LISTS);
ProgressiveMediaSource progressiveMediaSource =
new ProgressiveMediaSource.Factory(dataSourceFactory, extractorsFactory)
.createMediaSource(videoUri);
// playerView = new PlayerView(this);
playerView.setPlayer(exoPlayer);
exoPlayer.prepare(progressiveMediaSource);
exoPlayer.setPlayWhenReady(true);
PlayerControlView controlView = playerView.findViewById(R.id.exo_controller);
mFullScreenIcon = controlView.findViewById(R.id.exo_fullscreen_icon);
ImageView volumeControl = controlView.findViewById(R.id.exo_volume);
mFullScreenIcon.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(ORIENTATION ==Configuration.ORIENTATION_LANDSCAPE){
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
Timer mRestoreOrientation = new Timer();
mRestoreOrientation.schedule(new TimerTask() {
#Override
public void run() {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
}
}, 2000);
}
});
volumeControl.setOnClickListener(view -> {
float currentvolume = exoPlayer.getVolume();
if (currentvolume > 0f) {
previousVolume = currentvolume;
exoPlayer.setVolume(0f);
volumeControl.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_volume_off_white_24dp));
} else {
exoPlayer.setVolume(previousVolume);
volumeControl.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_volume_up_white_24dp));
}
});
} catch (Exception e) {
e.printStackTrace();
Log.d("MainExcep", e.getMessage());
}
}
#Override
protected void onPause() {
super.onPause();
if (exoPlayer!=null) {
exoPlayer.stop();
mLastPosition = exoPlayer.getCurrentPosition();
}
}
#Override
protected void onResume() {
super.onResume();
initiatePlayer();
if(mLastPosition!=0){
exoPlayer.seekTo(mLastPosition);
}
}
In my case, if i minimize or try to move from the this player video app to another app. The video player app always starting play from 0. I was try and succesfully, the video player app playing video from the last current position when you minimalize or move to another app, and this it.
go to
private void buildPlayer(String mp4Url)
add
player.seekTo(playbackPosition);
and then
#Override
public void onResume() {
super.onResume();
if(playbackPosition!=0 && player!=null){
player.seekTo(playbackPosition);
initializePlayer();
}
}
#Override
public void onPause() {
super.onPause();
player.stop();
if(player != null && player.getPlayWhenReady()) {
player.stop();
playbackPosition = player.getCurrentPosition();
player.setPlayWhenReady(true);
}
}
#Override
public void onStop() {
super.onStop();
player.setPlayWhenReady(false);
player.stop();
player.seekTo(0);
}
And you can try remove the
exoPlayer.setPlayWhenReady(true);
from
private void buildPlayer(String mp4Url)
I want to immediately start playing a sound when the activity is first launched and I want the MediaPlayerControl object to reflect this change. On the code given below the controls will start with play-mode activated instead of pause-mode (since the file is already playing).
public class Guide extends AppCompatActivity implements MediaPlayerControl, MediaPlayer.OnPreparedListener {
private MediaPlayer m_audio_player;
private MediaController m_audio_controller;
private Handler handler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_guide);
set_up_audio();
}
private void set_up_audio(){
m_audio_player = MediaPlayer.create(this, *SOMESOUNDFILE*);
m_audio_player.setOnPreparedListener(this);
m_audio_controller = new MediaController(this);
}
public void onPrepared(MediaPlayer mediaPlayer) {
m_audio_controller.setMediaPlayer(this);
m_audio_controller.setAnchorView(findViewById(R.id.main_audio_view));
handler.post(new Runnable() {
public void run() {
m_audio_controller.setEnabled(true);
m_audio_controller.show();
m_audio_player.start();
// how do I update m_audio_controller's state here?
}
});
}
}
how can I do this?
I've found the solution. If I call show after first having started the player, it does work.
m_audio_player.start();
m_audio_controller.show();
I'm sure this error is because I don't fully understand threads, but here it goes...
I have a runnable that is started when onCreate() is called within a method:
#Override
protected void onCreate(Bundle savedInstanceState) {
//Set all app specific starting points here
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_avatar);
...
soundMeterLoop();
}
public void soundMeterLoop() {
Log.d("SpeechKit", "Start Sound Meter");
soundMeterHandler = new Handler();
soundMeterRunnable = new Runnable() {
#Override
public void run() {
if(!soundMeter.SoundMeterRunning) {
Log.d("SpeechKit", "Start SoundMeter in the runnable");
startSoundMeter();
}
if (soundMeter.mMediaRecorder != null) {
amplitude = soundMeter.getAmplitude();
decibelLevelOutput.setText("" + amplitude);
if (amplitude > threshold) {
decibelLevelOutput.setTextColor(Color.RED);
Log.d("SpeechKit", "Interrupt and run startNuance()");
startNuance();
} else {
decibelLevelOutput.setTextColor(Color.BLACK);
Log.d("SpeechKit", "Running");
soundMeterHandler.postDelayed(this, 100);
}
}
}
};
soundMeterHandler.postDelayed(soundMeterRunnable, 100);
}
This runs just fine when it's created in the onCreate. As you can see, it kills itself (by not renewing the loop if the statement fails) and runs startNuance().
public void startNuance() {
soundMeterHandler.removeCallbacksAndMessages(soundMeterRunnable);
nuance.toggleReco();
}
I then kill the runnable and start a method in another class. This class runs fine, then when it's finished doing its thing, I call back to this main class with avatar.stopNuance();
This is in the Nuance.java class
#Override
public void onFinishedRecording(Transaction transaction) {
Log.d("SpeechKit", "onFinishedRecording");
//We have finished recording the users voice.
//We should update our state and stop polling their volume.
state = State.PROCESSING;
stopAudioLevelPoll();
avatar.stopNuance(); // <<<<<
}
It then returns back to my main activity (avatar) and runs this stopNuance() method:
public void stopNuance() {
Log.d("SpeechKit", "stopNuance(), start loop again");
soundMeterLoop();
}
Then it tries to run the same loop from before. Only this time, I'm getting a lot of errors that pertain to nullpointerexceptions. specifically starting with decibelLevelOutput.setText("" + amplitude);
I'm not sure why these things are null or how to fix them. Is this because it started a new thread that was not started in the creation of the runnable?
After talking on chat the actual issue was elsewhere in the codebase.
The problem was this:
public class Nuance {
private Activity activity;
private Session session;
public Avatar avatarActivity = new Avatar(); // DONT DO THIS
....
#Override
public void onFinishedRecording(Transaction transaction) {
Log.d("SpeechKit", "onFinishedRecording");
//We have finished recording the users voice.
//We should update our state and stop polling their volume.
state = State.PROCESSING;
stopAudioLevelPoll();
avatarActivity.stopNuance();
}
You should never, ever ever create your own instance of an Activity. They are creted and managed by the system. The system will call the lifecycle methods on the instance (onCreate etc) but if you create an instance these methods are not called - therefore a lot of strange behaviour happens.
The fix here is this:
public class Nuance {
private Avatar activity;
private Session session;
....
#Override
public void onFinishedRecording(Transaction transaction) {
Log.d("SpeechKit", "onFinishedRecording");
//We have finished recording the users voice.
//We should update our state and stop polling their volume.
state = State.PROCESSING;
stopAudioLevelPoll();
activity.stopNuance();
}
you don't want to create a new runnable everytime soundMeterLoop() is called.
Try this:
private final Handler soundMeterHandler = new Handler();
#Override
protected void onCreate(Bundle savedInstanceState) {
//Set all app specific starting points here
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_avatar);
...
soundMeterLoop();
}
public void soundMeterLoop() {
Log.d("SpeechKit", "Start Sound Meter");
soundMeterHandler.postDelayed(soundMeterRunnable, 100);
}
private final Runnable soundMeterRunnable = new Runnable() {
#Override
public void run() {
if(!soundMeter.SoundMeterRunning) {
Log.d("SpeechKit", "Start SoundMeter in the runnable");
startSoundMeter();
}
if (soundMeter.mMediaRecorder != null) {
amplitude = soundMeter.getAmplitude();
decibelLevelOutput.setText("" + amplitude);
if (amplitude > threshold) {
decibelLevelOutput.setTextColor(Color.RED);
Log.d("SpeechKit", "Interrupt and run startNuance()");
startNuance();
} else {
decibelLevelOutput.setTextColor(Color.BLACK);
Log.d("SpeechKit", "Running");
soundMeterHandler.postDelayed(this, 100);
}
}
}
};
I'm new to Android programming and am building a simple app that plays a sound from a local file when you flip the phone over, using a SensorListener for the accelerometer. Additionally, there's an image with a click listener that also plays the same sound when touched.
My code has the following sequence:
onCreate and onRestart - call MediaPlayer.create() for the local file.
onDestroy - call MediaPlayer.release and set the reference to null.
I'm debugging the app on my phone since the emulator doesn't support accelerometers.
When I click the image, I get a start called in state 64 error in Logcat, and when I flip the phone, the app FCs with a NullPointerException when mp.start() is called.
My understanding of how it works, from the MediaPlayer documentation is that you have to call create(), which in turn calls prepare() before you can start or stop the player. Is there a problem with the sequence of steps?
I've also tried releasing the media player in onStop, to no avail.
I have the following sensor listener for the accelerometer (mp is the MediaPlayer object) -
private final SensorEventListener accelerometerListener = new SensorEventListener() {
#Override
public void onSensorChanged(SensorEvent arg0) {
float z_value = arg0.values[2];
if (z_value < 0 && playerReady) {
mp.start(); // <-- NullPointerException thrown here.
} else {
mp.stop();
}
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
};
..and the following click listener for the button -
private final View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (playerReady) {
mp.start();
}
}
};
I also wrote an onPreparedListener for the media player (which sets the playerReady seen above)
private final OnPreparedListener opl = new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
playerReady = true;
}
};
Edit Here's onCreate() and onRestart() -
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mp = MediaPlayer.create(Moo.this, R.raw.moo);
mp.setOnPreparedListener(opl);
ImageView im = (ImageView) findViewById(R.id.imageView1);
im.setOnClickListener(onClickListener);
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
List<Sensor> sensorList = sensorManager
.getSensorList(Sensor.TYPE_ACCELEROMETER);
if (sensorList.size() > 0) {
accelerometerPresent = true;
accelerometerSensor = sensorList.get(0);
sensorManager.registerListener(accelerometerListener,
accelerometerSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
}
#Override
protected void onRestart() {
super.onRestart();
mp = MediaPlayer.create(Moo.this, R.raw.moo);
}
I have a Service which is performing a data update. I have an activity which attaches a listener to the service (via a local binding). The listener receives progress updates. Upon receiving a progress update, it schedules a runnable to be run on the UI thread. Here's the code (updated to show the full listing):
public class MyActivity extends Activity {
static final int UPDATE_DIALOG = 0;
ProgressDialog updateDialog;
private TaskService taskService;
private ServiceConnection taskServiceConnection = new ServiceConnection() {
private final TaskServiceObserver taskServiceObserver = new TaskServiceObserver() {
public void updateProgress(final int progress, final int total) {
runOnUiThread(new Runnable() {
public void run() {
if (updateDialog == null || !updateDialog.isShowing()) {
showDialog(UPDATE_DIALOG);
}
updateDialog.setProgress(progress);
}
});
}
public void updateCompleted() {
runOnUiThread(new Runnable() {
public void run() {
dismissDialog(UPDATE_DIALOG);
startNextActivity();
}
});
}
};
public void onServiceConnected(ComponentName name, IBinder binder) {
taskService = ((LocalBinder) binder).getService();
taskService.addObserver(taskServiceObserver);
}
public void onServiceDisconnected(ComponentName name) {
taskService.removeObserver(taskServiceObserver);
taskService = null;
}
};
protected void onStart() {
super.onStart();
Intent intent = new Intent(this, TaskService.class);
startService(intent);
bindService(intent, taskServiceConnection, Context.BIND_AUTO_CREATE);
}
protected void onStop() {
super.onStop();
if (taskService != null) {
unbindService(taskServiceConnection);
}
}
protected Dialog onCreateDialog(int id) {
switch (id) {
case UPDATE_DIALOG:
updateDialog = new ProgressDialog(this);
updateDialog.setTitle("My App");
updateDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
updateDialog.setMessage("Preparing to run for the first time...");
return updateDialog;
default:
return null;
}
}
}
If I tap the home button while the dialog is showing, then return to the app, I get a crash on the showDialog line. With the debugger I was able to determine that the activity is in the finished state.
What would be an appropriate check to put in my runnable which would determine whether it is safe to call showDialog?
I would personnally dismiss the progress dialog when the activity goes to pause (override onPause) and recreate it if necessary when the activity is resumed (override onResume). You could be leaking memory by keeping references to your activity in other separate objects (your dialog)
You should detach the listener in the onPause method so that since your activity is going into the background, the listener won't fire and try to update the UI.
The solution I ended up going with was to create a flag taskServiceBound which was set to true after binding to the service in onStart and set to false before unbinding from the service in onStop. Because the flag is updated on the UI thread, I can use it to gate the Runnables in updateProgress and updateCompleted. For example:
public void updateCompleted() {
runOnUiThread(new Runnable() {
public void run() {
if (taskServiceBound) {
dismissDialog(UPDATE_DIALOG);
startNextActivity();
}
}
});
}