OK -- I am using Android Studio 3.0 and YouTube API version 3 in my project.
I have added the library/jar files to the project (via this link).
The project compiles.
Here is the weird thing I cannot figure out: When I run the app and select a video, the app says "An error occurred while initializing YouTube player" This happens on device and emulator.
I looked at the IDE, I looked at the logcat and all I find is this error message on the IDE itself:
And I see this in the upper part of the IDE as well:
What is it that I have done wrong and how can I fix it so I can play the YouTube videos when they are selected?
I have added my YouTube activity file code here:
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import android.widget.VideoView;
import com.google.android.youtube.player.YouTubeBaseActivity;
import com.google.android.youtube.player.YouTubeInitializationResult;
import com.google.android.youtube.player.YouTubePlayer;
import com.google.android.youtube.player.YouTubePlayerView;
public class YouTubePlaybackOverlayActivity extends YouTubeBaseActivity implements YouTubePlayer.OnInitializedListener {
private static String ytUrl;
public String TAG = YouTubePlaybackOverlayActivity.class.getSimpleName();
public VideoView mVideoView;
public LeanbackPlaybackState mPlaybackState = LeanbackPlaybackState.IDLE;
public static final String API_KEY = "XXXXXXXXXXXXXXXXXXXX";
private int mPosition = 0;
private long mStartTimeMillis;
private long mDuration = -1;
/**
* ATTENTION: This was auto-generated to implement the App Indexing API.
* See https://g.co/AppIndexing/AndroidStudio for more information.
*/
//private GoogleApiClient client;
#Override
public void onStart() {
super.onStart();
// // ATTENTION: This was auto-generated to implement the App Indexing API.
// // See https://g.co/AppIndexing/AndroidStudio for more information.
// client.connect();
// Action viewAction = Action.newAction(
// Action.TYPE_VIEW, // TODO: choose an action type.
// "PlaybackOverlay Page", // TODO: Define a title for the content shown.
// // TODO: If you have web page content that matches this app activity's content,
// // make sure this auto-generated web page URL is correct.
// // Otherwise, set the URL to null.
// Uri.parse("http://host/path"),
// // TODO: Make sure this auto-generated app deep link URI is correct.
// Uri.parse("android-app://software.blackstone.sunnahstreamtv/http/host/path")
// );
// AppIndex.AppIndexApi.start(client, viewAction);
}
#Override
public void onStop() {
super.onStop();
// // ATTENTION: This was auto-generated to implement the App Indexing API.
// // See https://g.co/AppIndexing/AndroidStudio for more information.
// Action viewAction = Action.newAction(
// Action.TYPE_VIEW, // TODO: choose an action type.
// "PlaybackOverlay Page", // TODO: Define a title for the content shown.
// // TODO: If you have web page content that matches this app activity's content,
// // make sure this auto-generated web page URL is correct.
// // Otherwise, set the URL to null.
// Uri.parse("http://host/path"),
// // TODO: Make sure this auto-generated app deep link URI is correct.
// Uri.parse("android-app://software.blackstone.sunnahstreamtv/http/host/path")
// );
// AppIndex.AppIndexApi.end(client, viewAction);
// client.disconnect();
}
/*
* List of various states that we can be in
*/
public enum LeanbackPlaybackState {
PLAYING, PAUSED, IDLE
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/** attaching layout xml **/
//setContentView(R.layout.nabawi_video);
//setContentView(R.layout.activity_playback_overlay);
setContentView(R.layout.video_playback);
/** Initializing YouTube player view **/
YouTubePlayerView youTubePlayerView = (YouTubePlayerView) findViewById(R.id.youtube_player);
youTubePlayerView.initialize(API_KEY, this);
// ATTENTION: This was auto-generated to implement the App Indexing API.
// See https://g.co/AppIndexing/AndroidStudio for more information.
//client = new GoogleApiClient.Builder(this).addApi(AppIndex.API).build();
}
// #Override
// protected void onCreate(Bundle savedInstanceState) {
// super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_playback_overlay);
//
// loadViews();
// }
#Override
public void onDestroy() {
stopPlayback();
super.onDestroy();
}
private void loadViews() {
mVideoView = (VideoView) findViewById(R.id.youtube_player);
mVideoView.setFocusable(false);
mVideoView.setFocusableInTouchMode(false);
Movie movie = (Movie) getIntent().getSerializableExtra(DetailsActivity.MOVIE);
//setVideoPath(movie.getVideoUrl());
setVideoPath(movie.getyTubeID());
ytUrl = movie.getyTubeID();
}
public void setVideoPath(String videoUrl) {
setPosition(0);
mVideoView.setVideoPath(videoUrl);
mStartTimeMillis = 0;
mDuration = Utils.getDuration(videoUrl);
}
private void stopPlayback() {
if (mVideoView != null) {
mVideoView.stopPlayback();
}
}
private void setPosition(int position) {
if (position > mDuration) {
mPosition = (int) mDuration;
} else if (position < 0) {
mPosition = 0;
mStartTimeMillis = System.currentTimeMillis();
} else {
mPosition = position;
}
mStartTimeMillis = System.currentTimeMillis();
Log.d(TAG, "position set to " + mPosition);
}
public int getPosition() {
return mPosition;
}
public void setPlaybackState(LeanbackPlaybackState playbackState) {
this.mPlaybackState = playbackState;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_playback_overlay, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void playPause(boolean doPlay) {
if (mPlaybackState == LeanbackPlaybackState.IDLE) {
/* Callbacks for mVideoView */
setupCallbacks();
}
if (doPlay && mPlaybackState != LeanbackPlaybackState.PLAYING) {
mPlaybackState = LeanbackPlaybackState.PLAYING;
if (mPosition > 0) {
mVideoView.seekTo(mPosition);
}
mVideoView.start();
mStartTimeMillis = System.currentTimeMillis();
} else {
mPlaybackState = LeanbackPlaybackState.PAUSED;
int timeElapsedSinceStart = (int) (System.currentTimeMillis() - mStartTimeMillis);
setPosition(mPosition + timeElapsedSinceStart);
mVideoView.pause();
}
}
public void fastForward() {
if (mDuration != -1) {
// Fast forward 10 seconds.
setPosition(mVideoView.getCurrentPosition() + (10 * 1000));
mVideoView.seekTo(mPosition);
}
}
public void rewind() {
// rewind 10 seconds
setPosition(mVideoView.getCurrentPosition() - (10 * 1000));
mVideoView.seekTo(mPosition);
}
private void setupCallbacks() {
mVideoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
#Override
public boolean onError(MediaPlayer mp, int what, int extra) {
mVideoView.stopPlayback();
mPlaybackState = LeanbackPlaybackState.IDLE;
return false;
}
});
mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
if (mPlaybackState == LeanbackPlaybackState.PLAYING) {
mVideoView.start();
}
}
});
mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
mPlaybackState = LeanbackPlaybackState.IDLE;
}
});
}
#Override
public void onInitializationFailure(YouTubePlayer.Provider provider, YouTubeInitializationResult result) {
Toast.makeText(this, "Failured to Initialize!", Toast.LENGTH_LONG).show();
}
#Override
public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer player, boolean wasRestored) {
/** add listeners to YouTubePlayer instance **/
player.setPlayerStateChangeListener(playerStateChangeListener);
player.setPlaybackEventListener(playbackEventListener);
player.setFullscreen(true);
player.setPlayerStyle(YouTubePlayer.PlayerStyle.CHROMELESS);
//player.play();
/** Start buffering **/
for (int i = 0; i < MovieProvider.mItems.size(); i++) {
Movie movie = (Movie) getIntent().getSerializableExtra(DetailsActivity.MOVIE);
player.loadVideo(movie.getyTubeID());
}
}
private YouTubePlayer.PlaybackEventListener playbackEventListener = new YouTubePlayer.PlaybackEventListener() {
#Override
public void onBuffering(boolean arg0) {
}
#Override
public void onPaused() {
}
#Override
public void onPlaying() {
}
#Override
public void onSeekTo(int arg0) {
}
#Override
public void onStopped() {
}
};
private YouTubePlayer.PlayerStateChangeListener playerStateChangeListener = new YouTubePlayer.PlayerStateChangeListener() {
#Override
public void onAdStarted() {
}
#Override
public void onError(YouTubePlayer.ErrorReason arg0) {
}
#Override
public void onLoaded(String arg0) {
}
#Override
public void onLoading() {
}
#Override
public void onVideoEnded() {
}
#Override
public void onVideoStarted() {
}
};
}
The issue was a corrout indexing in the project.
I removed the class file.
Then I cleared the cache, restarted Android Studio and then cleaned and rebuilt the project.
I restarted Android Studio again and then recreated the desired class file(s) and layout files and the project compiled successfully and everything is good.
Thanks everyone for your time, advice, advice and input.
Related
I have an app which plays video from youtube and i have coded the link in my MainActivity class..
I have made the video played in my app as expected..
I have tried PictureInPictureParams.Builder but ran into multiple errors..
public class MainActivity extends YouTubeBaseActivity implements
YouTubePlayer.OnInitializedListener {
private static final int RECOVERY_REQUEST = 1;
private YouTubePlayerView youTubeView;
private MyPlayerStateChangeListener playerStateChangeListener;
private MyPlaybackEventListener playbackEventListener;
private YouTubePlayer player;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
youTubeView = (YouTubePlayerView) findViewById(R.id.youtube_view);
youTubeView.initialize(Config.YOUTUBE_API_KEY, this);
playerStateChangeListener = new MyPlayerStateChangeListener();
playbackEventListener = new MyPlaybackEventListener();
final EditText seekToText = (EditText) findViewById(R.id.seek_to_text);
Button seekToButton = (Button) findViewById(R.id.seek_to_button);
seekToButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int skipToSecs = Integer.valueOf(seekToText.getText().toString());
player.seekToMillis(skipToSecs * 1000);
}
});
}
#Override
public void onInitializationSuccess(Provider provider, YouTubePlayer player, boolean wasRestored) {
this.player = player;
player.setPlayerStateChangeListener(playerStateChangeListener);
player.setPlaybackEventListener(playbackEventListener);
if (!wasRestored) {
player.cueVideo("I0D-fkypQQw"); // Plays https://www.youtube.com/watch?v=fhWaJi1Hsfo
}
}
#Override
public void onInitializationFailure(Provider provider, YouTubeInitializationResult errorReason) {
if (errorReason.isUserRecoverableError()) {
errorReason.getErrorDialog(this, RECOVERY_REQUEST).show();
} else {
String error = String.format(getString(R.string.player_error), errorReason.toString());
Toast.makeText(this, error, Toast.LENGTH_LONG).show();
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECOVERY_REQUEST) {
// Retry initialization if user performed a recovery action
getYouTubePlayerProvider().initialize(Config.YOUTUBE_API_KEY, this);
}
}
protected Provider getYouTubePlayerProvider() {
return youTubeView;
}
private void showMessage(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
private final class MyPlaybackEventListener implements YouTubePlayer.PlaybackEventListener {
#Override
public void onPlaying() {
// Called when playback starts, either due to user action or call to play().
showMessage("Playing");
}
#Override
public void onPaused() {
// Called when playback is paused, either due to user action or call to pause().
showMessage("Paused");
}
#Override
public void onStopped() {
// Called when playback stops for a reason other than being paused.
showMessage("Stopped");
}
#Override
public void onBuffering(boolean b) {
// Called when buffering starts or ends.
}
#Override
public void onSeekTo(int i) {
// Called when a jump in playback position occurs, either
// due to user scrubbing or call to seekRelativeMillis() or seekToMillis()
}
}
private final class MyPlayerStateChangeListener implements YouTubePlayer.PlayerStateChangeListener {
#Override
public void onLoading() {
// Called when the player is loading a video
// At this point, it's not ready to accept commands affecting playback such as play() or pause()
}
#Override
public void onLoaded(String s) {
// Called when a video is done loading.
// Playback methods such as play(), pause() or seekToMillis(int) may be called after this callback.
}
#Override
public void onAdStarted() {
// Called when playback of an advertisement starts.
}
#Override
public void onVideoStarted() {
// Called when playback of the video starts.
}
#Override
public void onVideoEnded() {
// Called when the video reaches its end.
}
#Override
public void onError(YouTubePlayer.ErrorReason errorReason) {
// Called when an error occurs.
}
}
}
How do I implement picture in picture mode for the video where the video shrinks to the bottom right corner of the app..
Now i get is the youtue video played in the activity.. what i expect is to make the video play in picture-in-picture mode
I solved my problem using PictureInPictureParams as follows
First i created a Button (enter_pip) in my xml and in the OnClick i coded the following :
enter_pip.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (android.os.Build.VERSION.SDK_INT >= 26) {
//Trigger PiP mode
try {
Rational rational = new Rational(youTubeView.getWidth(), youTubeView.getHeight());
PictureInPictureParams mParams =
new PictureInPictureParams.Builder()
.setAspectRatio(rational)
.build();
enterPictureInPictureMode(mParams);
} catch (IllegalStateException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "API 26 needed to perform PiP", Toast.LENGTH_SHORT).show();
}
}
});
I also added the following attributes in my AndroidManifest to my PipActivity to support Picture in Picture in my Activity
<activity
android:name=".PipActivity"
android:launchMode="singleTask"
android:supportsPictureInPicture="true"
android:theme="#style/AppTheme.NoActionBar" />
I'm trying to using Cleveroad WaveInApp in my Application
https://github.com/Cleveroad/WaveInApp everything is working fine as I want but when Song Completed it also stops mediaPlayer.setOnCompletionListener(which works fine when I removed this code).
When I try to change the song it crashes.
Error :-
java.lang.NullPointerException: Attempt to invoke interface method 'void com.cleveroad.audiovisualization.InnerAudioVisualization.stopRendering()' on a null object reference
at com.cleveroad.audiovisualization.DbmHandler.stopRendering(DbmHandler.java:61)
at com.cleveroad.audiovisualization.DbmHandler$2.onCalmedDown(DbmHandler.java:82)
at com.cleveroad.audiovisualization.GLAudioVisualizationView$1.onCalmedDown(GLAudioVisualizationView.java:49)
at com.cleveroad.audiovisualization.GLRenderer.onDrawFrame(GLRenderer.java:87)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1608)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1299)
MainContainer.class
public class MainContainer extends AppCompatActivity
implements
NavigationView.OnNavigationItemSelectedListener,
SeekBar.OnSeekBarChangeListener {
private static final String LOGTAG = "Friday";
public static final String isPlay = "isPlay";
public static final String NOTIFICATION_ACTION = "Notification_Action";
private static final String VOLUME_BUTTON = "android.media.VOLUME_CHANGED_ACTION";
SlidingUpPanelLayout slideLayout;
MusicService mService;
boolean mBound = false;
Timer t = new Timer();
SeekBar seekBar;
ImageView albumArt;
ImageView panelAlbumart;
TextView songname;
TextView singername;
TextView seekCurrentDuration;
TextView seekTotalDuration;
TextView panelSongname;
TextView panelSingername;
ImageView playBtn;
IntentFilter mIntentFilter;
RelativeLayout panelHead;
SeekBar volumeControl;
AudioManager audioManager;
AudioVisualization audioVisualization;
VisualizerDbmHandler vizualizerHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main_container);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
setVolumeControlStream(AudioManager.STREAM_MUSIC); //best practice to set volume control
DrawerLayout drawer = findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
ViewPager vp_pages = findViewById(R.id.vp_pages);
PagerAdapter pagerAdapter = new FragmentAdapter(getSupportFragmentManager());
vp_pages.setAdapter(pagerAdapter);
mIntentFilter = new IntentFilter();
mIntentFilter.addAction(isPlay);
mIntentFilter.addAction(VOLUME_BUTTON);
mIntentFilter.addAction(NOTIFICATION_ACTION);
TabLayout tbl_pages = findViewById(R.id.tbl_pages);
tbl_pages.setupWithViewPager(vp_pages);
seekBar = findViewById(R.id.seek_bar_red);
seekBar.setOnSeekBarChangeListener(this);
}
#Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main_container, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onStart() {
super.onStart();
// Bind to LocalService
Intent intent = new Intent(this, MusicService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
}
#Override
protected void onStop() {
super.onStop();
unbindService(mConnection);
mBound = false;
}
// control Volume by Seekbar
private void volumeControl() {
volumeControl = findViewById(devil.jarvis.friday.R.id.volume_control);
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
if (audioManager != null) {
volumeControl.setMax(audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC));
volumeControl.setProgress(audioManager.getStreamVolume(AudioManager.STREAM_MUSIC));
}
volumeControl.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, i, 0);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
#Override
public void onResume() {
super.onResume();
registerReceiver(mReceiver, mIntentFilter);
init();
//todo add this when song is played
audioVisualization.onResume();
updateUI();
volumeControl();
}
#Override
public void onPause() {
audioVisualization.onPause();
unregisterReceiver(mReceiver);
super.onPause();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
private void init() {
albumArt = findViewById(R.id.musicArt);
panelAlbumart = findViewById(R.id.slidePanelArt);
songname = findViewById(R.id.song_name);
singername = findViewById(R.id.singer_name);
panelSingername = findViewById(R.id.singer_name_head);
panelSongname = findViewById(R.id.song_name_head);
seekCurrentDuration = findViewById(R.id.current_time);
seekTotalDuration = findViewById(R.id.song_duration);
playBtn = findViewById(R.id.play);
panelHead = findViewById(R.id.header);
slideLayout = findViewById(R.id.sliding_layout);
audioVisualization = findViewById(R.id.visualizer_view);
}
public void updateUI() {
//Update UI
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (mBound) {
try {
setupMusicUI(mService.getCurrentDuration(), mService.getDuration());
} catch (Exception e) {
//
}
}
}
}, 0, 1000);
}
private void setupMusicUI(int currentDuration, int duration) {
seekBar.setMax(duration);
seekBar.setProgress(currentDuration);
}
// code for update song details
private void updateTextInfo() {
if (mBound) {
int pos = mService.getPosition();
panelSongname.setText(arrayList.get(pos));
panelSingername.setText(artistName.get(pos));
songname.setText(arrayList.get(pos));
singername.setText(artistName.get(pos));
//update album art with text also
updateAlbumArt();
changePlayBtn();
startEqualiser();
// try{
// startEqualiser();
// }catch (Exception e){
// //
// }
}
}
private void setSeekbarTime(int position, int duration) {
int curr_time_seconds = (position / 1000) % 60;
int curr_time_minutes = (position / 1000) / 60;
int dur_time_seconds = (duration / 1000) % 60;
int dur_time_minutes = (duration / 1000) / 60;
String current_zero_minutes = "0";
String current_zero_seconds = "0";
String duration_zero_minues = "0";
String duration_zero_seconds = "0";
if (curr_time_minutes > 9)
current_zero_minutes = "";
if (curr_time_seconds > 9)
current_zero_seconds = "";
if (dur_time_minutes > 9)
duration_zero_minues = "";
if (dur_time_seconds > 9)
duration_zero_seconds = "";
seekCurrentDuration.setText(current_zero_minutes + curr_time_minutes + ":" + current_zero_seconds + curr_time_seconds);
seekTotalDuration.setText(duration_zero_minues + dur_time_minutes + ":" + duration_zero_seconds + dur_time_seconds);
}
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(VOLUME_BUTTON)) {
volumeControl();
}
if (intent.getAction().equals(isPlay)) {
boolean show = intent.getBooleanExtra("showPanel", false);
if (show) {
//show Panel here
slideLayout.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
updateTextInfo();
}
} else if (intent.getAction().equals(NOTIFICATION_ACTION)) {
int action = intent.getIntExtra("action", 0);
switch (action) {
case 1:
changePlayBtn();
break;
case 2:
updateTextInfo();
break;
case 3:
updateTextInfo();
break;
case 4:
audioVisualization.release();
break;
default:
break;
}
}
}
};
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
/**
* Defines callbacks for service binding, passed to bindService()
*/
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className,
IBinder service) {
// We've bound to LocalService, cast the IBinder and get LocalService instance
MusicService.LocalBinder binder = (MusicService.LocalBinder) service;
mService = binder.getService();
mBound = true;
}
#Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
public void playBtn(View view) {
if (mBound) {
mService.play();
changePlayBtn();
}
}
private void changePlayBtn() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
playBtn.setImageResource(R.drawable.ic_pause_button);
} else {
playBtn.setImageResource(R.drawable.ic_play_arrow);
}
}
}
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
setSeekbarTime(i, mediaPlayer.getDuration());
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
mService.changeSeekTo(seekBar.getProgress());
}
public void previousBtn(View view) {
if (mBound) {
mService.previous();
updateTextInfo();
}
}
public void nextBtn(View view) {
if (mBound) {
mService.next();
updateTextInfo();
}
}
public void startEqualiser() {
try {
vizualizerHandler = VisualizerDbmHandler.Factory.newVisualizerHandler(getApplicationContext(), mediaPlayer);
audioVisualization.linkTo(vizualizerHandler);
} catch (Exception e) {
// TODO change it to snackbar message
Toast.makeText(mService, "Please Give Mic Permission", Toast.LENGTH_SHORT).show();
}
}
public void updateAlbumArt() {
Glide
.with(getApplicationContext())
.load(songThumb.get(musicPosition))
.placeholder(R.drawable.ic_default_icon)
.into(panelAlbumart);
Glide
.with(getApplicationContext())
.load(songThumb.get(musicPosition))
.placeholder(R.drawable.ic_default_icon)
.into(albumArt);
}
}
and this is my MusicService.class
public class MusicService extends MediaBrowserServiceCompat implements
MediaPlayer.OnCompletionListener,
AudioManager.OnAudioFocusChangeListener {
private static final String LOGTAG = "Friday";
public static int musicPosition;
public static MediaPlayer mediaPlayer;
Uri u;
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
Notification status;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getExtras() != null && intent.getExtras().containsKey("pos")) {
musicPosition = intent.getIntExtra("pos", 0);
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
}
if (arrayList != null) {
u = Uri.parse(songPath.get(musicPosition));
mediaPlayer = MediaPlayer.create(getApplicationContext(), u);
}
try {
playSong();
} catch (Exception e) {
next();
}
}
if (intent.getAction() != null) {
if (intent.getAction().equals(Constants.ACTION.PREV_ACTION)) {
previous();
} else if (intent.getAction().equals(Constants.ACTION.PLAY_ACTION)) {
play();
sendAction(1);
} else if (intent.getAction().equals(Constants.ACTION.NEXT_ACTION)) {
next();
}
}
return super.onStartCommand(intent, flags, startId);
}
private void playSong() {
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.start();
showNotification();
}
private void sendAction(int action){
/* 1 for play or pause
* 2 for next
* 3 for previous
*/
Intent intent = new Intent();
intent.setAction(MainContainer.NOTIFICATION_ACTION);
intent.putExtra("action",action);
sendBroadcast(intent);
}
public int getPosition() {
return musicPosition;
}
public int getCurrentDuration() {
return mediaPlayer.getCurrentPosition();
}
public int getDuration() {
return mediaPlayer.getDuration();
}
public void changeSeekTo(int progress) {
mediaPlayer.seekTo(progress);
}
/**
* Class used for the client Binder. Because we know this service always
* runs in the same process as its clients, we don't need to deal with IPC.
*/
public class LocalBinder extends Binder {
public MusicService getService() {
// Return this instance of LocalService so clients can call public methods
return MusicService.this;
}
}
public void next() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
musicPosition = (musicPosition + 1) % songPath.size();
u = Uri.parse(songPath.get(musicPosition));
mediaPlayer = MediaPlayer.create(getApplicationContext(), u);
playSong();
sendAction(2);
}
}
public void previous() {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
musicPosition = (musicPosition - 1 < 0) ? songPath.size() - 1 : musicPosition - 1;
u = Uri.parse(songPath.get(musicPosition));
mediaPlayer = MediaPlayer.create(getApplicationContext(), u);
playSong();
sendAction(3);
}
}
public void play() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
showNotification();
} else {
mediaPlayer.start();
showNotification();
}
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onAudioFocusChange(int i) {
mediaPlayer.stop();
}
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
sendAction(4);
next();
}
#Nullable
#Override
public BrowserRoot onGetRoot(#NonNull String clientPackageName, int clientUid, #Nullable Bundle rootHints) {
return null;
}
#Override
public void onLoadChildren(#NonNull String parentId, #NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
}
.
.
.
}
I don't know what happened.
Can anybody know about it.
There is already mediaPlayer.setOnCompleteListener inside VisualizerDbmHandler. So, for use it in other places you should use setInnerOnCompletionListener method to add own complete listener to VisualizerDbmHandler
Try do not recreate mediaPlayer but setup new source to it
**My conclusion is**: As you can see in source code of MediaPlayer - it will call onCompletion in cases that unhandled error appears). So, I think, because of recreating mediaPlayer in time, when you call startEqualizer ( recreate visualizerHandler and link it to visualizer view) inside the method linkTo - library call release to previous visualizerHandler and setup variable audioVisualizer to null, that provide you to calling stopRendering on null reference in case of onCompletion calling during to some error during reset/stop/release of MediaPlayer.
Native Android Media player does not invoke onCompletion method after the video has ran it's duration.
I have an Activity that plays a single video or a list of videos (m3u8 file). Video plays file as it should, I can use the media controller as well, however, when the video runs out, after a few seconds he starts a loop. onCompletion method doesn't activate unless the user clicks (or double taps) the fast forward option on media controler.
Is there a way to make the onComplete method activate automatically when the video runs out? (I've tried using the listener, doesn't work). Pointing out what I did wrong also works.
Here is the activity that handles video playing:
public class VideoActivity extends ActionBarActivity implements MediaPlayer.OnCompletionListener {
private static final String TAG = VideoActivity.class.getSimpleName();
private VideoView mVideoViewStream1;
ProgressDialog mDialog;
private String mURL;
private ChannelPlaylist mChannelPlaylist;
private int mIndex;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video);
// Validate internet connection
if (!Util.isDeviceConnected(this)) {
FragmentManager fm = getSupportFragmentManager();
PopUpErrorFragment popupError = PopUpErrorFragment.newInstance(getString(R.string.errorInternetConnection));
popupError.show(fm, PopUpErrorFragment.TAG);
finish();
}
// Assign controls to their variable representations
mVideoViewStream1 = (VideoView) findViewById(R.id.vvVideo);
// Retrieve bundle data
Intent i = getIntent();
Bundle bundle = i.getExtras();
ChannelPlaylist channelPlaylist = bundle.getParcelable(KeyHelper.BUNDLE_CHANNEL_PLAYLIST);
if (channelPlaylist != null) {
this.mChannelPlaylist = channelPlaylist;
if (bundle.containsKey("index") && mIndex == 0) {
this.mIndex = bundle.getInt("index");
} else {
if (this.mIndex == 0) {
this.mIndex = this.mChannelPlaylist.getIndex();
}
}
this.mURL = this.mChannelPlaylist.getSchedule().get(mIndex).getStream_url();
} else {
this.mURL = bundle.getString("url");
}
progressDialog();
standardAndroidPlayer();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.video, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
/***************************** CLASS METHODS **************************************************/
/**
* Dismissess the dialog
*/
private void dismissDialog() {
if (this.mDialog != null) {
mDialog.dismiss();
}
}
/**
* Standard android player
*/
private void standardAndroidPlayer() {
try {
// Start the MediaController
MediaController mediacontroller = new MediaController(this);
mediacontroller.setAnchorView(mVideoViewStream1);
// Get the URL from String VideoURL
mVideoViewStream1.setMediaController(mediacontroller);
// Set media player completion listener
mVideoViewStream1.setOnCompletionListener(this);
mVideoViewStream1.setVideoURI(Uri.parse(this.mURL));
mVideoViewStream1.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
//Log.i(TAG, "Duration = " + mVideoViewStream1.getDuration());
if (mp.isLooping()) mp.setLooping(false);
}
});
mVideoViewStream1.requestFocus();
mVideoViewStream1.start();
} catch (Exception e) {
dismissDialog();
Log.e(TAG, "Error" + e.getMessage());
e.printStackTrace();
}
dismissDialog();
}
#Override
public void onCompletion(MediaPlayer mp) {
this.mIndex++;
if (this.mIndex < mChannelPlaylist.getSchedule().size()) {
this.mURL = this.mChannelPlaylist.getSchedule().get(this.mIndex).getStream_url();
standardAndroidPlayer();
} else {
finish();
}
}
/**
* Creates a progress dialog
*/
private void progressDialog() {
// Create a progressbar
mDialog = new ProgressDialog(VideoActivity.this);
// Set progressbar title
mDialog.setTitle("Android Video Streaming Tutorial");
// Set progressbar message
mDialog.setMessage("Buffering...");
mDialog.setIndeterminate(false);
mDialog.setCancelable(false);
// Show progressbar
mDialog.show();
}
}
Edited:
Ok, for some strange reason, on mobile phone the method doesn't fire off, however when used on tablet, it does. I wasn't able to reproduce the effect on tablet and didn't have any success on the phone either. Does it have something to do with the versions of android? Since I didn't get any warnings about compatibility when writing the listener, I didn't think much about it.
Try this.
mVideoViewStream1.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
finish();
}
});
I have created media player run time I have change url but surface view is black and expected url is not playing i got some error in my logcat i have posted my error and media player code. why it's happening?
code :
public class MediaPlayerActivity extends Activity implements
SurfaceHolder.Callback, OnCompletionListener, OnClickListener {
/**
* MediaPlayer Field
*/
private MediaPlayer mediaPlayer;
/**
* surfaceHolder Field
*/
private SurfaceHolder surfaceHolder;
/**
* playerSurfaceView Field
*/
private SurfaceView playerSurfaceView;
/**
* wifiUSerName Field
*/
private static String wifiUSerName = "RMS";
/**
* List of Url Field
*/
private static List<Playfile> urls;
/**
* Button previous
*/
private Button prevButton;
/**
* Button play And Pause
*/
private Button playAndPauseButton;
/**
* Button Next
*/
private Button nextButton;
/**
* seekbar Field
*/
private SeekBar seekbar;
/**
* currentIndex Field
*/
private int currentIndex = 0;
/**
* PlayMode boolean
*/
private boolean isPlayMode = false;
/**
* FooterLayoutShow boolean
*/
private boolean isFooterLayoutShow = false;
/**
* progressDialog Field
*/
private ProgressDialog progressDialog;
/**
* Runnable Field to run on Every Second
*/
private Runnable onEverySecond = null;
/**
* FrameLayout Field
*/
private FrameLayout rootFrameLayout;
/**
* RelativeLayout footerButton
*/
private RelativeLayout footerButtonLayout;
// private ProgressBar progBar;
/**
* Method is called at very first time. set ui.
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_media_player);
initViewControls();
getDataFromBundle();
/*
* if (MainActivity.progress.isShowing()) {
* MainActivity.progress.dismiss(); }
*/
mediaPlayer = new MediaPlayer();
}
/**
* Method is used to initialize media player object and flag, set default
* text on button.
*/
#Override
protected void onStart() {
// TODO Auto-generated method stub
super.onStart();
mediaPlayer = new MediaPlayer();
isPlayMode = true;
playAndPauseButton.setBackgroundResource(R.drawable.pause);
// Reset Urls
urls = MasterData.getValueBasedOnKey(wifiUSerName);
}
/**
* Method is used to get data from bundle.
*/
private void getDataFromBundle() {
if (getIntent().getExtras() != null) {
Bundle bundle = getIntent().getExtras();
wifiUSerName = bundle.getString("wifiusername");
urls = MasterData.getValueBasedOnKey(wifiUSerName);
} else {
showToast("No data available");
// Take the user to home
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_HOME);
homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(homeIntent);
}
}
/**
* Method is used to initialise view controls.
*/
private void initViewControls() {
playerSurfaceView = (SurfaceView) findViewById(R.id.playersurface);
prevButton = (Button) findViewById(R.id.activity_mediaplayer_prev_btn);
playAndPauseButton = (Button) findViewById(R.id.activity_mediaplayer_play_and_pause_btn);
nextButton = (Button) findViewById(R.id.activity_mediaplayer_next_btn);
seekbar = (SeekBar) findViewById(R.id.activity_mediaplayer_seekbar);
rootFrameLayout = (FrameLayout) findViewById(R.id.activity_media_player_root_layout);
footerButtonLayout = (RelativeLayout) findViewById(R.id.activity_mediaplayer_footer_button_layout);
footerButtonLayout.setVisibility(View.GONE);
prevButton.setOnClickListener(this);
playAndPauseButton.setOnClickListener(this);
nextButton.setOnClickListener(this);
surfaceHolder = playerSurfaceView.getHolder();
surfaceHolder.addCallback(this);
seekbar.setVisibility(View.INVISIBLE);
rootFrameLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
seekbar.setVisibility(View.INVISIBLE);
if (!isFooterLayoutShow) {
isFooterLayoutShow = true;
footerButtonLayout.setVisibility(View.VISIBLE);
} else {
isFooterLayoutShow = false;
footerButtonLayout.setVisibility(View.INVISIBLE);
}
} else {
seekbar.setVisibility(View.VISIBLE);
}
return true;
}
});
//
// showProgressDialog();
}
/**
* Surface Holder Callback Methods
*/
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder arg0) {
try {
playMediaPlayer();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
Utils.writeToSDCard("Exception -" + e.getMessage());
} catch (SecurityException e) {
// TODO Auto-generated catch block
Utils.writeToSDCard("Exception -" + e.getMessage());
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
Utils.writeToSDCard("Exception -" + e.getMessage());
}
}
/**
* Method is used to play media file.
*/
private void playMediaPlayer() {
if (urls != null) {
try {
if (currentIndex < urls.size()) {
//
// showProgressDialog();
if (mediaPlayer == null) {
mediaPlayer = new MediaPlayer();
}
mediaPlayer.reset();
mediaPlayer.setDisplay(surfaceHolder);
/*
* System.out.println(" url :: " +
* urls.get(currentIndex).getUrl());
*/
boolean a=MasterData.songtest;
/*if(MasterData.songtest){
mediaPlayer.setDataSource("http://122.165.94.246/rms/trans.mp4");
}else{*/
Log.e("print","for url :"+MasterData.songtest+urls.get(currentIndex).getUrl());
mediaPlayer.setDataSource(urls.get(currentIndex).getUrl());
/*}*/
showToast("Preparing media player");
//mediaPlayer.prepareAsync();
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer
.setOnBufferingUpdateListener(new OnBufferingUpdateListener() {
#Override
public void onBufferingUpdate(MediaPlayer mp,
int percent) {
// TODO Auto-generated method stub
//
// if(percent == 100){
// stopProgressDialog();
// }else {
// showProgressDialog();
// }
}
});
// ****************************************
mediaPlayer.setOnPreparedListener(new OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
/*
* if (progressDialog != null &&
* progressDialog.isShowing()) {
* progressDialog.dismiss(); }
*/
seekbar.setMax(mediaPlayer.getDuration());
seekbar.postDelayed(onEverySecond, 1000);
mediaPlayer.start();
// stopProgressDialog();
}
});
onEverySecond = new Runnable() {
#Override
public void run() {
if (seekbar != null && mediaPlayer != null) {
seekbar.setProgress(mediaPlayer
.getCurrentPosition());
}
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
seekbar.postDelayed(onEverySecond, 1000);
}
}
};
seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onProgressChanged(SeekBar seekBar,
int progress, boolean fromUser) {
if (fromUser) {
// this is when actually seekbar has been seeked
// to a new position
mediaPlayer.seekTo(progress);
}
}
});
// ***************************************
} /*
* else { mediaPlayer.stop(); mediaPlayer.reset();
* playAndPauseButton.setBackgroundResource(R.drawable.stop); }
*/
} catch (IllegalStateException e) {
} catch (Exception e) {
Utils.writeToSDCard("Exception -" + e.getMessage());
// showToast("Some error occured!");
// stopProgressDialog();
}
} else {
showToast("No urls list present.Download xml file");
// stopProgressDialog();
// finish();
startActivity(new Intent(this, MainActivity.class));
}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying())
mediaPlayer.stop();
mediaPlayer.reset();
}
}
/**
* Listner for Media File on Completion
*/
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
currentIndex++;
progressDialog = null;
playMediaPlayer();
}
#Override
protected void onDestroy() {
super.onDestroy();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer.release();
mediaPlayer = null;
}
}
/*#Override
protected void onPause() {
super.onPause();
}*/
/**
* Method is used to controls all click event on view portion.
*/
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.activity_mediaplayer_next_btn:
progressDialog = null;
if (mediaPlayer != null) {
playNextVideo();
}
break;
case R.id.activity_mediaplayer_prev_btn:
progressDialog = null;
if (mediaPlayer != null) {
playPrevVideo();
}
break;
case R.id.activity_mediaplayer_play_and_pause_btn:
playAndPauseVideo();
break;
default:
break;
}
}
/**
* Method is used to play and pause media player based on click event.
*/
private void playAndPauseVideo() {
if (isPlayMode) {
isPlayMode = false;
playAndPauseButton.setBackgroundResource(R.drawable.play);
if (mediaPlayer != null && mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
} else {
isPlayMode = true;
playAndPauseButton.setBackgroundResource(R.drawable.pause);
if (mediaPlayer != null) {
mediaPlayer.start();
}
}
}
/**
* Method is used to play previous video.
*/
private void playPrevVideo() {
if (currentIndex > 0) {
//
// showProgressDialog();
currentIndex--;
playMediaPlayer();
} else {
showToast("No Prev Video Present.");
}
}
/**
* Method is used to play next video.
*/
private void playNextVideo() {
if (currentIndex < urls.size() - 1) {
//
// showProgressDialog();
currentIndex++;
playMediaPlayer();
} else {
showToast("No Next Video Present.");
}
}
/**
* Method is used to show toast based on message param.
*
* #param message
*/
private void showToast(String message) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
/**
* Method is used to show progress dialog.
*/
private void showProgressDialog() {
if (progressDialog == null) {
progressDialog = ProgressDialog.show(this, "", "Buffering...");
}
}
/**
* Method is used to stop progress dialog.
*/
private void stopProgressDialog() {
if (progressDialog != null) {
progressDialog.dismiss();
progressDialog = null;
}
}
#Override
protected void onStop() {
// TODO Auto-generated method stub
super.onStop();
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.reset();
mediaPlayer = null;
}
}
}
Edit***
still looking for an answer to my original question. Why won't Android see the item has been bought previously instead of making the user pay again? Setting SharedPreferences is an OK idea, but what if the user uninstalls? They would have to buy again. I do not want this for the users. Thank you.
I tried to figure out why the app does not inventory correctly, I took this from TrivialDrive and tried to make it my own. I believe I removed all the consume and I only have one item to purchase; a premium upgrade. This should be bought only once and never charged twice. When I compile and run the app on my tablet I pass the purchase process OK and all seems well, until I use the task manager to close the app and re-open it. Once it's re-opened it asks to purchase premium again instead of passing that and performing the premium function.
Here is the code:
public class myClass extends SherlockActivity {
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mDrawerToggle;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
private String[] mPlanetTitles;
public static final int DIALOG_DOWNLOAD_PROGRESS = 0;
ProgressBar pd = null;
private ProgressDialog mProgressDialog;
Spinner spLoadFrom;
WebView wv;
private LinearLayout container;
private Button nextButton, closeButton;
private EditText findBox;
private static final String TAG = "Web";
IabHelper mHelper;
static boolean mIsPremium = false;
boolean mIsUserPremium = false;
boolean searchAllowed = false;
static final String PREM_SKU = "prem";
private ArrayAdapter<CharSequence> spinnerArrayAdapter;
String name_free[] = { };
String displayName_free[] = { };
String name_premium[] = { };
String displayName_premium[] = {};
/** Called when the activity is first created. */
#SuppressLint("NewApi")
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mylayout);
mTitle = mDrawerTitle = getTitle();
mPlanetTitles = getResources().getStringArray(
R.array.fMenu);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
// set a custom shadow that overlays the main content when the drawer
// opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this,
R.layout.drawer_list_item, mPlanetTitles));
mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
// enable ActionBar app icon to behave as action to toggle nav drawer
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the sliding drawer and the action bar app icon
mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
R.string.drawer_open, /* "open drawer" description for accessibility */
R.string.drawer_close /* "close drawer" description for accessibility */
) {
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle(mTitle);
supportInvalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle(mDrawerTitle);
supportInvalidateOptionsMenu(); // creates call to
// onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
if (savedInstanceState == null) {
selectItem(0);
}
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setIndeterminate(false);
mProgressDialog.setMax(100);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
wv = (WebView) findViewById(R.id.webview);
pd = (ProgressBar) findViewById(R.id.pBar);
spLoadFrom = (Spinner) findViewById(R.id.Spinner02);
if (mIsPremium == true) {
spinnerArrayAdapter = new ArrayAdapter<CharSequence>(this,
android.R.layout.simple_spinner_item, displayName_premium);
} else {
spinnerArrayAdapter = new ArrayAdapter<CharSequence>(this,
android.R.layout.simple_spinner_item, displayName_free);
}
spinnerArrayAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spLoadFrom.setAdapter(spinnerArrayAdapter);
SpinnerListener spListener = new SpinnerListener();
spLoadFrom.setOnItemSelectedListener(spListener);
String base64EncodedPublicKey = "hidden";
mHelper = new IabHelper(this, base64EncodedPublicKey);
Log.d(TAG, "Starting setup.");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
#Override
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
// Oh noes, there was a problem.
complain("Problem setting up in-app billing: " + result);
return;
}
// Hooray, IAB is fully set up. Now, let's get an inventory of
// stuff we own.
Log.d(TAG, "Setup successful. Querying inventory.");
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getSupportMenuInflater().inflate(R.menu.menu3, menu);
return super.onCreateOptionsMenu(menu);
}
/* Called whenever we call invalidateOptionsMenu() */
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content
// view
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(final MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(getMenuItem(item))) {
return true;
}
int itemId = item.getItemId();
if (itemId == R.id.search) {
if (searchAllowed == false) {
} else if (itemId == R.id.contact) {
emailme();
} else if (itemId == R.id.rate) {
Uri uri = Uri.parse("market://details?id=" + getPackageName());
Intent myAppLinkToMarket = new Intent(Intent.ACTION_VIEW, uri);
try {
startActivity(myAppLinkToMarket);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "Unable to find Play Market",
Toast.LENGTH_SHORT).show();
}
}
return super.onOptionsItemSelected(item);
}
public void buyPrem() {
Log.d(TAG,
"Upgrade button clicked; launching purchase flow for upgrade.");
/*
* TODO: for security, generate your payload here for verification. See
* the comments on verifyDeveloperPayload() for more info. Since this is
* a SAMPLE, we just use an empty string, but on a production app you
* should carefully generate this.
*/
String payload = "";
mHelper.launchPurchaseFlow(this, PREM_SKU, 10001,
mPurchaseFinishedListener, payload);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + ","
+ data);
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
} else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
#Override
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: "
+ purchase);
if (result.isFailure()) {
complain("Error purchasing: " + result);
// Handle error
return;
}
if (!verifyDeveloperPayload(purchase)) {
complain("Error purchasing. Authenticity verification failed.");
return;
}
Log.d(TAG, "Purchase successful.");
if (purchase.getSku().equals(PREM_SKU)) {
// bought the premium upgrade!
Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
alert("Thank you for upgrading to premium!");
mIsPremium = true;
mIsUserPremium = true;
searchAllowed = true;
}
}
};
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
Log.d(TAG, "Query inventory finished.");
if (result.isFailure()) {
complain("Failed to query inventory: " + result);
return;
}
/*if (inventory.hasPurchase(PREM_SKU)) {
mHelper.consumeAsync(inventory.getPurchase(PREM_SKU), null);
}*/
Log.d(TAG, "Query inventory was successful.");
Purchase premiumPurchase = inventory.getPurchase(PREM_SKU);
mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));
if (mIsPremium) {
searchAllowed = true;
mIsUserPremium = true;
Log.d(TAG, "Should be premium by now...");
}
Log.d(TAG, "Initial inventory query finished; enabling main UI.");
}
};
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
/*
* TODO: verify that the developer payload of the purchase is correct.
* It will be the same one that you sent when initiating the purchase.
*
* WARNING: Locally generating a random string when starting a purchase
* and verifying it here might seem like a good approach, but this will
* fail in the case where the user purchases an item on one device and
* then uses your app on a different device, because on the other device
* you will not have access to the random string you originally
* generated.
*
* So a good developer payload has these characteristics:
*
* 1. If two different users purchase an item, the payload is different
* between them, so that one user's purchase can't be replayed to
* another user.
*
* 2. The payload must be such that you can verify it even when the app
* wasn't the one who initiated the purchase flow (so that items
* purchased by the user on one device work on other devices owned by
* the user).
*
* Using your own server to store and verify developer payloads across
* app installations is recommended.
*/
return true;
}
/*public void consumeItem() {
mHelper.queryInventoryAsync(mReceivedInventoryListener);
}*/
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
#Override
public void onQueryInventoryFinished(IabResult result,
Inventory inventory) {
if (result.isFailure()) {
// Handle failure
} else {
searchAllowed = false;
//mHelper.consumeAsync(inventory.getPurchase(PREM_SKU),
// mConsumeFinishedListener);
}
}
};
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
#Override
public void onConsumeFinished(Purchase purchase, IabResult result) {
if (result.isSuccess()) {
} else {
// handle error
}
}
};
#Override
public void onDestroy() {
super.onDestroy();
if (mHelper != null)
mHelper.dispose();
mHelper = null;
}
void complain(String message) {
Log.e(TAG, "**** TrivialDrive Error: " + message);
alert("Error: " + message);
}
void alert(String message) {
AlertDialog.Builder bld = new AlertDialog.Builder(this);
bld.setMessage(message);
bld.setNeutralButton("OK", null);
Log.d(TAG, "Showing alert dialog: " + message);
bld.create().show();
}
private android.view.MenuItem getMenuItem(final MenuItem item) {
return new android.view.MenuItem() {
#Override
public int getItemId() {
return item.getItemId();
}
public boolean isEnabled() {
return true;
}
#Override
public boolean collapseActionView() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean expandActionView() {
// TODO Auto-generated method stub
return false;
}
#Override
public ActionProvider getActionProvider() {
// TODO Auto-generated method stub
return null;
}
#Override
public View getActionView() {
// TODO Auto-generated method stub
return null;
}
#Override
public char getAlphabeticShortcut() {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getGroupId() {
// TODO Auto-generated method stub
return 0;
}
#Override
public Drawable getIcon() {
// TODO Auto-generated method stub
return null;
}
#Override
public Intent getIntent() {
// TODO Auto-generated method stub
return null;
}
#Override
public ContextMenuInfo getMenuInfo() {
// TODO Auto-generated method stub
return null;
}
#Override
public char getNumericShortcut() {
// TODO Auto-generated method stub
return 0;
}
#Override
public int getOrder() {
// TODO Auto-generated method stub
return 0;
}
#Override
public SubMenu getSubMenu() {
// TODO Auto-generated method stub
return null;
}
#Override
public CharSequence getTitle() {
// TODO Auto-generated method stub
return null;
}
#Override
public CharSequence getTitleCondensed() {
// TODO Auto-generated method stub
return null;
}
#Override
public boolean hasSubMenu() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isActionViewExpanded() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isCheckable() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isChecked() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean isVisible() {
// TODO Auto-generated method stub
return false;
}
#Override
public android.view.MenuItem setActionProvider(
ActionProvider actionProvider) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setActionView(View view) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setActionView(int resId) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setAlphabeticShortcut(char alphaChar) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setCheckable(boolean checkable) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setChecked(boolean checked) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setEnabled(boolean enabled) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setIcon(Drawable icon) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setIcon(int iconRes) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setIntent(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setNumericShortcut(char numericChar) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setOnActionExpandListener(
OnActionExpandListener listener) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setOnMenuItemClickListener(
OnMenuItemClickListener menuItemClickListener) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setShortcut(char numericChar,
char alphaChar) {
// TODO Auto-generated method stub
return null;
}
#Override
public void setShowAsAction(int actionEnum) {
// TODO Auto-generated method stub
}
#Override
public android.view.MenuItem setShowAsActionFlags(int actionEnum) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setTitle(CharSequence title) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setTitle(int title) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setTitleCondensed(CharSequence title) {
// TODO Auto-generated method stub
return null;
}
#Override
public android.view.MenuItem setVisible(boolean visible) {
// TODO Auto-generated method stub
return null;
}
};
}
private class DrawerItemClickListener implements
ListView.OnItemClickListener {
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
switch (position) {
case 0:
mDrawerLayout.closeDrawer(mDrawerList);
break;
case 1:
Intent c1 = new Intent(getBaseContext(), 1.class);
startActivity(c1);
break;
case 2:
Intent c2 = new Intent(getBaseContext(), 5.class);
startActivity(c2);
break;
case 3:
Intent c3 = new Intent(getBaseContext(), 3.class);
startActivity(c3);
break;
case 4:
Intent c4 = new Intent(getBaseContext(), 4.class);
startActivity(c4);
break;
default:
}
}
}
public void selectItem(int position) {
switch (position) {
case 0:
break;
case 1:
setContentView(R.layout.1);
break;
case 2:
setContentView(R.layout.2);
break;
case 3:
setContentView(R.layout.3);
break;
case 4:
setContentView(R.layout.4);
break;
default:
}
}
#Override
public void setTitle(CharSequence title) {
mTitle = title;
getSupportActionBar().setTitle(mTitle);
}
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
By closing your application you delete all variables, including mIsPremium.
Therefor you need to save the value of mIsPremium somewhere and load it when you again open the application.
I suggest you to use SharedPreferences for this task.
That's how you could do this:
In the IabHelper.OnIabPurchaseFinishedListener you need to save your preference:
if (purchase.getSku().equals(PREM_SKU)) {
// bought the premium upgrade!
Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
alert("Thank you for upgrading to premium!");
mIsPremium = true;
mIsUserPremium = true;
searchAllowed = true;
SharedPreferences prefs = this.getBaseContext().getSharedPreferences(
"com.example.yourapp", 0);
prefs.edit().putBoolean("premium", true).apply;
}
Here you save the premium state "true" to the shared preference "premium" after the user has sucessfully purchased premium.
In the onCreate() method you need to load the preference:
SharedPreferences prefs = this.getBaseContext().getSharedPreferences(
"com.example.yourapp", 0);
mIsPremium = prefs.getBoolean("premium", false);
Here you load the preference "premium", if this prefernce does not exist yet, it will take "false" als default value.
While the answers provided by both #Philip Sheard and #Al0x were excellent my problem was solved by a review of my code. I entirely removed any reference to the "consume" process. It was a simple fix but I also incorporated the SharedPreferences and all is well. Thanks to all the suggestions - You led me to the correct places!
Another solution is to add a button to your in-app store, that allows the user to restore all his purchases. This procedure is described in the IAB v3 docs, and Apple mandates such an approach.